func.c 44.3 KB
Newer Older
Arturo Espinosa's avatar
Arturo Espinosa committed
1
/*
Jody Goldberg's avatar
Jody Goldberg committed
2
 * func.c: Function management and utility routines.
Arturo Espinosa's avatar
Arturo Espinosa committed
3 4 5
 *
 * Author:
 *  Miguel de Icaza (miguel@gnu.org)
6
 *  Michael Meeks   (mmeeks@gnu.org)
Morten Welinder's avatar
Morten Welinder committed
7
 *  Morten Welinder (terra@gnome.org)
8
 *  Jody Goldberg   (jody@gnome.org)
Arturo Espinosa's avatar
Arturo Espinosa committed
9
 */
10

11
#include <gnumeric-config.h>
12
#include <glib/gi18n-lib.h>
13
#include <glib/gstdio.h>
14
#include <gnm-i18n.h>
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
#include <gnumeric.h>
#include <func.h>

#include <parse-util.h>
#include <dependent.h>
#include <expr.h>
#include <expr-impl.h>
#include <expr-name.h>
#include <cell.h>
#include <workbook-priv.h>
#include <sheet.h>
#include <value.h>
#include <number-match.h>
#include <func-builtin.h>
#include <command-context-stderr.h>
#include <gnm-plugin.h>
#include <gutils.h>
#include <gui-util.h>
33
#include <gnm-marshalers.h>
34

35
#include <goffice/goffice.h>
36
#include <glib.h>
37
#include <string.h>
38 39
#include <stdlib.h>

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
enum {
	PROP_0,
	PROP_NAME,
	PROP_TRANSLATION_DOMAIN,
	PROP_IN_USE,
};

enum {
	SIG_LOAD_STUB,
	SIG_LINK_DEP,
	LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };


55
#define F2(func,s) dgettext ((func)->tdomain->str, (s))
56

57
static GList	    *categories;
58
static GnmFuncGroup *unknown_cat;
Jody Goldberg's avatar
Jody Goldberg committed
59

60 61 62
static GHashTable *functions_by_name;
static GHashTable *functions_by_localized_name;

63 64 65
/**
 * functions_init: (skip)
 */
Jody Goldberg's avatar
Jody Goldberg committed
66 67 68
void
functions_init (void)
{
69 70 71 72 73 74 75
	functions_by_name =
		g_hash_table_new (go_ascii_strcase_hash, go_ascii_strcase_equal);

	/* FIXME: ascii???  */
	functions_by_localized_name =
		g_hash_table_new (go_ascii_strcase_hash, go_ascii_strcase_equal);

76 77 78
	func_builtin_init ();
}

79 80 81
/**
 * functions_shutdown: (skip)
 */
82 83 84
void
functions_shutdown (void)
{
85 86
	while (unknown_cat != NULL && unknown_cat->functions != NULL) {
		GnmFunc *func = unknown_cat->functions->data;
87 88
		if (func->usage_count > 0) {
			g_warning ("Function %s still has %d users.\n",
89
				   gnm_func_get_name (func, FALSE),
90 91
				   func->usage_count);
			func->usage_count = 0;
92
		}
93
		g_object_unref (func);
94
	}
95
	func_builtin_shutdown ();
96

97 98 99 100 101
	g_hash_table_destroy (functions_by_name);
	functions_by_name = NULL;

	g_hash_table_destroy (functions_by_localized_name);
	functions_by_localized_name = NULL;
Jody Goldberg's avatar
Jody Goldberg committed
102
}
103

104 105 106 107 108
/**
 * gnm_func_enumerate:
 *
 * Return value: (element-type GnmFunc) (transfer container):
 */
109 110
GPtrArray *
gnm_func_enumerate (void)
111
{
112 113 114
	GPtrArray *res = g_ptr_array_new ();
	GHashTableIter hiter;
	gpointer value;
115

116 117 118
	g_hash_table_iter_init (&hiter, functions_by_name);
	while (g_hash_table_iter_next (&hiter, NULL, &value))
		g_ptr_array_add (res, value);
119

120
	return res;
Jody Goldberg's avatar
Jody Goldberg committed
121 122
}

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
static GnmValue *
error_function_no_full_info (GnmFuncEvalInfo *ei,
			     int argc,
			     GnmExprConstPtr const *argv)
{
	return value_new_error (ei->pos, _("Function implementation not available."));
}

static void
gnm_func_load_stub (GnmFunc *func)
{
	g_return_if_fail (func->fn_type == GNM_FUNC_TYPE_STUB);

	g_signal_emit (G_OBJECT (func), signals[SIG_LOAD_STUB], 0);

	if (func->fn_type == GNM_FUNC_TYPE_STUB) {
		static GnmFuncHelp const no_help[] = { { GNM_FUNC_HELP_END } };

		func->help = no_help;
Morten Welinder's avatar
Morten Welinder committed
142
		gnm_func_set_varargs (func, error_function_no_full_info);
143 144 145
	}
}

146 147
inline void
gnm_func_load_if_stub (GnmFunc *func)
148
{
149 150
	if (func->fn_type == GNM_FUNC_TYPE_STUB)
		gnm_func_load_stub (func);
151 152
}

153
static char *
154
split_at_colon (char const *s, char **rest)
155 156 157 158 159 160 161 162 163 164 165 166
{
	char *dup = g_strdup (s);
	char *colon = strchr (dup, ':');
	if (colon) {
		*colon = 0;
		if (rest) *rest = colon + 1;
	} else {
		if (rest) *rest = NULL;
	}
	return dup;
}

167 168
/* ------------------------------------------------------------------------- */

169 170 171 172 173 174
static void
gnm_func_group_free (GnmFuncGroup *fn_group)
{
	g_return_if_fail (fn_group != NULL);
	g_return_if_fail (fn_group->functions == NULL);

175 176 177
	if (fn_group->ref_count-- > 1)
		return;

178 179
	go_string_unref (fn_group->internal_name);
	go_string_unref (fn_group->display_name);
180 181 182
	g_free (fn_group);
}

183
static GnmFuncGroup *
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
gnm_func_group_ref (GnmFuncGroup *fn_group)
{
	fn_group->ref_count++;
	return fn_group;
}

GType
gnm_func_group_get_type (void)
{
	static GType t = 0;

	if (t == 0) {
		t = g_boxed_type_register_static ("GnmFuncGroup",
			 (GBoxedCopyFunc)gnm_func_group_ref,
			 (GBoxedFreeFunc)gnm_func_group_free);
	}
	return t;
}

Jody Goldberg's avatar
Jody Goldberg committed
203 204 205
static gint
function_category_compare (gconstpointer a, gconstpointer b)
{
206 207
	GnmFuncGroup const *cat_a = a;
	GnmFuncGroup const *cat_b = b;
Jody Goldberg's avatar
Jody Goldberg committed
208

209
	return go_string_cmp (cat_a->display_name, cat_b->display_name);
210 211
}

212
GnmFuncGroup *
213
gnm_func_group_fetch (char const *name, char const *translation)
214
{
215
	GnmFuncGroup *cat = NULL;
216
	GList *l;
217

218
	g_return_val_if_fail (name != NULL, NULL);
219

220 221
	for (l = categories; l != NULL; l = l->next) {
		cat = l->data;
222
		if (strcmp (cat->internal_name->str, name) == 0) {
223 224 225 226 227
			break;
		}
	}

	if (l == NULL) {
228
		cat = g_new (GnmFuncGroup, 1);
229
		cat->internal_name = go_string_new (name);
230
		cat->ref_count = 1;
231
		if (translation != NULL) {
232
			cat->display_name = go_string_new (translation);
233 234
			cat->has_translation = TRUE;
		} else {
235
			cat->display_name = go_string_new (name);
236 237 238 239
			cat->has_translation = FALSE;
		}
		cat->functions = NULL;
		categories = g_list_insert_sorted (
240
			     categories, cat, &function_category_compare);
241
	} else if (translation != NULL && translation != name &&
242
		   !cat->has_translation) {
243 244
		go_string_unref (cat->display_name);
		cat->display_name = go_string_new (translation);
245
		cat->has_translation = TRUE;
Morten Welinder's avatar
Morten Welinder committed
246
		categories = g_list_remove_link (categories, l);
247 248
		g_list_free_1 (l);
		categories = g_list_insert_sorted (
249
			     categories, cat, &function_category_compare);
250
	}
Morten Welinder's avatar
Morten Welinder committed
251

Jody Goldberg's avatar
Jody Goldberg committed
252 253
	return cat;
}
Morten Welinder's avatar
Morten Welinder committed
254

255 256
GnmFuncGroup *
gnm_func_group_get_nth (int n)
Jody Goldberg's avatar
Jody Goldberg committed
257 258 259
{
	return g_list_nth_data (categories, n);
}
Morten Welinder's avatar
Morten Welinder committed
260

261
static void
262
gnm_func_group_add_func (GnmFuncGroup *fn_group, GnmFunc *fn_def)
263
{
264 265
	g_return_if_fail (fn_group != NULL);
	g_return_if_fail (fn_def != NULL);
266

267
	fn_group->functions = g_slist_prepend (fn_group->functions, fn_def);
268 269
}

270 271 272 273 274 275 276 277 278 279 280
static void
gnm_func_group_remove_func (GnmFuncGroup *fn_group, GnmFunc *fn_def)
{
	g_return_if_fail (fn_group != NULL);
	g_return_if_fail (fn_def != NULL);

	fn_group->functions = g_slist_remove (fn_group->functions, fn_def);
	if (fn_group->functions == NULL) {
		categories = g_list_remove (categories, fn_group);
		if (unknown_cat == fn_group)
			unknown_cat = NULL;
281
		gnm_func_group_free (fn_group);
282 283 284
	}
}

Jody Goldberg's avatar
Jody Goldberg committed
285 286
/******************************************************************************/

Morten Welinder's avatar
Morten Welinder committed
287 288
static void
gnm_func_create_arg_names (GnmFunc *fn_def)
289 290 291 292
{
	int i;
	GPtrArray *ptr;

Morten Welinder's avatar
Morten Welinder committed
293
	g_return_if_fail (fn_def != NULL);
294 295

	ptr = g_ptr_array_new ();
296 297 298 299 300 301 302 303 304 305
	for (i = 0;
	     fn_def->help && fn_def->help[i].type != GNM_FUNC_HELP_END;
	     i++) {
		if (fn_def->help[i].type != GNM_FUNC_HELP_ARG)
			continue;

		g_ptr_array_add
			(ptr, split_at_colon
			 (F2(fn_def, fn_def->help[i].text), NULL));
	}
Morten Welinder's avatar
Morten Welinder committed
306

Morten Welinder's avatar
Morten Welinder committed
307
	fn_def->arg_names = ptr;
308 309
}

310
gboolean
Morten Welinder's avatar
Morten Welinder committed
311
gnm_func_is_varargs (GnmFunc *func)
312
{
313 314 315
	gnm_func_load_stub (func);
	return func->fn_type == GNM_FUNC_TYPE_NODES;
}
316

317
gboolean
Morten Welinder's avatar
Morten Welinder committed
318
gnm_func_is_fixargs (GnmFunc *func)
319 320 321
{
	gnm_func_load_stub (func);
	return func->fn_type == GNM_FUNC_TYPE_ARGS;
322 323 324
}

void
Morten Welinder's avatar
Morten Welinder committed
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
gnm_func_set_stub (GnmFunc *func)
{
	func->fn_type = GNM_FUNC_TYPE_STUB;

	g_free (func->arg_spec);
	func->arg_spec = NULL;

	g_free (func->arg_types);
	func->arg_types = NULL;

	if (func->arg_names) {
		g_ptr_array_foreach (func->arg_names, (GFunc)g_free, NULL);
		g_ptr_array_free (func->arg_names, TRUE);
		func->arg_names = NULL;
	}

	func->min_args = func->max_args = 0;

	func->nodes_func = NULL;
	func->args_func = NULL;
}

/**
 * gnm_func_set_varargs: (skip)
 * @func: #GnmFunc
 * @fn: evaluation function
 */
void
gnm_func_set_varargs (GnmFunc *func, GnmFuncNodes fn)
354 355
{
	g_return_if_fail (GNM_IS_FUNC (func));
Morten Welinder's avatar
Morten Welinder committed
356
	g_return_if_fail (fn != NULL);
357

Morten Welinder's avatar
Morten Welinder committed
358
	gnm_func_set_stub (func); // Clear out stuff
359

Morten Welinder's avatar
Morten Welinder committed
360 361 362 363
	func->fn_type = GNM_FUNC_TYPE_NODES;
	func->nodes_func = fn;
	func->min_args = 0;
	func->min_args = G_MAXINT;
364 365
}

Morten Welinder's avatar
Morten Welinder committed
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
/**
 * gnm_func_set_fixargs: (skip)
 * @func: #GnmFunc
 * @fn: evaluation function
 * @spec: argument type specification
 */
void
gnm_func_set_fixargs (GnmFunc *func, GnmFuncArgs fn, const char *spec)
{
	char *p;

	g_return_if_fail (GNM_IS_FUNC (func));
	g_return_if_fail (fn != NULL);
	g_return_if_fail (spec != NULL);

	gnm_func_set_stub (func); // Clear out stuff

	func->fn_type = GNM_FUNC_TYPE_ARGS;
	func->args_func = fn;
	func->arg_spec = g_strdup (spec);

	func->arg_types = g_strdup (func->arg_spec);
	p = strchr (func->arg_types, '|');
	if (p) {
		func->min_args = p - func->arg_types;
		memmove (p, p + 1, strlen (p));
	} else
		func->min_args = 0;
	func->max_args = strlen (func->arg_types);

	gnm_func_create_arg_names (func);
}
398

399 400 401 402 403
static void
gnm_func_set_localized_name (GnmFunc *fd, const char *lname)
{
	gboolean in_hashes = !(fd->flags & GNM_FUNC_IS_WORKBOOK_LOCAL);

404 405 406
	if (g_strcmp0 (fd->localized_name, lname) == 0)
		return;

407 408 409 410 411 412 413 414 415 416
	if (in_hashes && fd->localized_name)
		g_hash_table_remove (functions_by_localized_name, fd->localized_name);
	g_free (fd->localized_name);

	fd->localized_name = g_strdup (lname);
	if (in_hashes && lname)
		g_hash_table_insert (functions_by_localized_name,
				     fd->localized_name, fd);
}

417 418
/**
 * gnm_func_inc_usage:
Morten Welinder's avatar
Morten Welinder committed
419
 * @func: #GnmFunc
420 421 422 423 424 425
 *
 * This function increments the usage count of @func.  A non-zero usage count
 * prevents the unloading of the function.
 *
 * Returns: (transfer full): a new reference to @func.
 */
426
GnmFunc *
427
gnm_func_inc_usage (GnmFunc *func)
428
{
429
	g_return_val_if_fail (func != NULL, NULL);
430

431
	func->usage_count++;
432 433
	if (func->usage_count == 1)
		g_object_notify (G_OBJECT (func), "in-use");
434
	return func;
Jody Goldberg's avatar
Jody Goldberg committed
435
}
436

437 438 439 440 441 442 443 444
/**
 * gnm_func_dec_usage:
 * @func: (transfer full): #GnmFunc
 *
 * This function decrements the usage count of @func.  When the usage count
 * reaches zero, the function may be unloaded, for example by unloading the
 * plugin that defines it.
 */
Jody Goldberg's avatar
Jody Goldberg committed
445
void
446
gnm_func_dec_usage (GnmFunc *func)
Jody Goldberg's avatar
Jody Goldberg committed
447
{
448
	g_return_if_fail (func != NULL);
449
	g_return_if_fail (func->usage_count > 0);
450

451
	func->usage_count--;
452 453
	if (func->usage_count == 0)
		g_object_notify (G_OBJECT (func), "in-use");
Jody Goldberg's avatar
Jody Goldberg committed
454
}
Morten Welinder's avatar
Morten Welinder committed
455

456 457
gboolean
gnm_func_get_in_use (GnmFunc *func)
458
{
459
	g_return_val_if_fail (func != NULL, FALSE);
460

461
	return func->usage_count > 0;
462 463
}

464 465 466 467 468 469 470 471

/**
 * gnm_func_lookup:
 * @name: name of function
 * @scope: (nullable): scope of function, %NULL for global
 *
 * Returns: (nullable) (transfer none): the function of that name.
 */
472
GnmFunc *
Jody Goldberg's avatar
Jody Goldberg committed
473
gnm_func_lookup (char const *name, Workbook *scope)
474
{
475 476 477 478 479 480 481 482
	GnmFunc *fd = g_hash_table_lookup (functions_by_name, name);
	if (fd != NULL)
		return fd;
	if (scope == NULL || scope->sheet_local_functions == NULL)
		return NULL;
	return g_hash_table_lookup (scope->sheet_local_functions, (gpointer)name);
}

483 484 485 486 487 488 489
/**
 * gnm_func_lookup_localized:
 * @name: localized name of function
 * @scope: (nullable): scope of function, %NULL for global
 *
 * Returns: (nullable) (transfer none): the function of that name.
 */
490 491 492 493
GnmFunc *
gnm_func_lookup_localized (char const *name, Workbook *scope)
{
	GnmFunc *fd;
494
	GHashTableIter hiter;
495 496
	gpointer value;

497
	/* Must localize all function names.  */
498 499 500 501 502 503 504 505 506
	g_hash_table_iter_init (&hiter, functions_by_name);
	while (g_hash_table_iter_next (&hiter, NULL, &value)) {
		GnmFunc *fd = value;
		(void)gnm_func_get_name (fd, TRUE);
	}

	fd = g_hash_table_lookup (functions_by_localized_name, name);
	if (fd != NULL)
		return fd;
507 508 509
	if (scope == NULL || scope->sheet_local_functions == NULL)
		return NULL;
	return g_hash_table_lookup (scope->sheet_local_functions, (gpointer)name);
510 511
}

512 513
/**
 * gnm_func_lookup_prefix:
514
 * @prefix: prefix to search for
515
 * @scope:
516
 * @trans: whether to search translated function names
517 518 519
 *
 * Returns: (element-type GnmFunc*) (transfer full):
 **/
520
GSList *
521
gnm_func_lookup_prefix (char const *prefix, Workbook *scope, gboolean trans)
522
{
523
	GSList *res = NULL;
524
	GHashTableIter hiter;
525
	gpointer value;
Morten Welinder's avatar
Morten Welinder committed
526

527 528 529 530 531 532 533
	/*
	 * Always iterate over functions_by_name as the localized name
	 * might not be set yet.
	 */
	g_hash_table_iter_init (&hiter, functions_by_name);
	while (g_hash_table_iter_next (&hiter, NULL, &value)) {
		GnmFunc *fd = value;
534 535 536
		if (!(fd->flags & GNM_FUNC_IS_PLACEHOLDER)) {
			const char *name = gnm_func_get_name (fd, trans);
			if (g_str_has_prefix (name, prefix)) {
537
				gnm_func_inc_usage (fd);
538 539
				res = g_slist_prepend (res, fd);
			}
540 541 542 543
		}
	}

	return res;
544 545
}

546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
/**
 * gnm_func_get_translation_domain:
 * @func: #GnmFunc
 *
 * Returns: (transfer none): the translation domain for @func's help text.
 */
char const *
gnm_func_get_translation_domain (GnmFunc *func)
{
	g_return_val_if_fail (GNM_IS_FUNC (func), NULL);
	return func->tdomain->str;
}

/**
 * gnm_func_set_translation_domain:
 * @func: #GnmFunc
 * @tdomain: (nullable): Translation domain, %NULL for Gnumeric's.
 */
void
gnm_func_set_translation_domain (GnmFunc *func, const char *tdomain)
{
	g_return_if_fail (GNM_IS_FUNC (func));

	if (!tdomain)
		tdomain = GETTEXT_PACKAGE;

	if (g_strcmp0 (func->tdomain->str, tdomain) == 0)
		return;

	go_string_unref (func->tdomain);
	func->tdomain = go_string_new (tdomain);

	g_object_notify (G_OBJECT (func), "translation-domain");
}

Morten Welinder's avatar
Morten Welinder committed
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
GnmFuncFlags
gnm_func_get_flags (GnmFunc *func)
{
	g_return_val_if_fail (GNM_IS_FUNC (func), GNM_FUNC_SIMPLE);
	return func->flags;
}

void
gnm_func_set_flags (GnmFunc *func, GnmFuncFlags f)
{
	g_return_if_fail (GNM_IS_FUNC (func));
	func->flags = f;
}

GnmFuncImplStatus
gnm_func_get_impl_status (GnmFunc *func)
{
	g_return_val_if_fail (GNM_IS_FUNC (func), GNM_FUNC_IMPL_STATUS_UNIMPLEMENTED);
	return func->impl_status;
}

void
gnm_func_set_impl_status (GnmFunc *func, GnmFuncImplStatus st)
{
	g_return_if_fail (GNM_IS_FUNC (func));
	func->impl_status = st;
}


GnmFuncTestStatus
gnm_func_get_test_status (GnmFunc *func)
{
	g_return_val_if_fail (GNM_IS_FUNC (func), GNM_FUNC_TEST_STATUS_UNKNOWN);
	return func->test_status;
}

void
gnm_func_set_test_status (GnmFunc *func, GnmFuncTestStatus st)
{
	g_return_if_fail (GNM_IS_FUNC (func));
	func->test_status = st;
}


625 626 627 628 629 630 631 632 633 634 635 636 637 638
/**
 * gnm_func_get_function_group:
 * @func: #GnmFunc
 *
 * Returns: (transfer none): the function group to which @func belongs.
 */
GnmFuncGroup *
gnm_func_get_function_group (GnmFunc *func)
{
	g_return_val_if_fail (GNM_IS_FUNC (func), NULL);
	return func->fn_group;
}


639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
void
gnm_func_set_function_group (GnmFunc *func, GnmFuncGroup *group)
{
	g_return_if_fail (GNM_IS_FUNC (func));
	g_return_if_fail (group != NULL);

	if (func->fn_group == group)
		return;

	if (func->fn_group)
		gnm_func_group_remove_func (func->fn_group, func);
	func->fn_group = group;
	gnm_func_group_add_func (group, func);

	if (group == unknown_cat)
		func->flags |= GNM_FUNC_IS_PLACEHOLDER;
	else
		func->flags &= ~GNM_FUNC_IS_PLACEHOLDER;
}



/**
 * gnm_func_add:
 * @group:
 * @descriptor:
 * @tdomain: (nullable):
 *
 * Returns: (transfer full): a new #GnmFunc.
 */
669
GnmFunc *
670
gnm_func_add (GnmFuncGroup *fn_group,
671
	      GnmFuncDescriptor const *desc,
672
	      const char *tdomain)
Jody Goldberg's avatar
Jody Goldberg committed
673
{
Morten Welinder's avatar
Morten Welinder committed
674
	//static char const valid_tokens[] = "fsbraAES?|";
675
	GnmFunc *func;
Jody Goldberg's avatar
Jody Goldberg committed
676

677
	g_return_val_if_fail (fn_group != NULL, NULL);
678
	g_return_val_if_fail (desc != NULL, NULL);
679

680 681 682 683
	func = g_object_new (GNM_FUNC_TYPE,
			     "name", desc->name,
			     NULL);
	gnm_func_set_translation_domain (func, tdomain);
684

685
	func->help		= desc->help ? desc->help : NULL;
686 687 688 689 690
	func->flags		= desc->flags;
	func->impl_status	= desc->impl_status;
	func->test_status	= desc->test_status;

	if (desc->fn_args != NULL) {
Morten Welinder's avatar
Morten Welinder committed
691
		gnm_func_set_fixargs (func, desc->fn_args, desc->arg_spec);
692
	} else if (desc->fn_nodes != NULL) {
Morten Welinder's avatar
Morten Welinder committed
693
		if (desc->arg_spec && *desc->arg_spec)
694
			g_warning ("Arg spec for node function -- why?");
Morten Welinder's avatar
Morten Welinder committed
695
		gnm_func_set_varargs (func, desc->fn_nodes);
696 697
	} else {
		g_warning ("Invalid function has neither args nor nodes handler");
698
		g_object_unref (func);
699
		return NULL;
700 701
	}

702
	func->fn_group = fn_group;
703
	gnm_func_group_add_func (fn_group, func);
704
	if (!(func->flags & GNM_FUNC_IS_WORKBOOK_LOCAL))
705 706
		g_hash_table_insert (functions_by_name,
				     (gpointer)(func->name), func);
707

708
	return func;
709 710
}

711
/* Handle unknown functions on import without losing their names */
Jody Goldberg's avatar
Jody Goldberg committed
712
static GnmValue *
713
unknownFunctionHandler (GnmFuncEvalInfo *ei,
714 715
			G_GNUC_UNUSED int argc,
			G_GNUC_UNUSED GnmExprConstPtr const *argv)
716
{
717
	return value_new_error_NAME (ei->pos);
718 719
}

720 721 722 723
static char *
invent_name (const char *pref, GHashTable *h, const char *template)
{
	static int count = 0;
724
	char *name = g_utf8_strdown (pref, -1);
725

726
	while (g_hash_table_lookup (h, name)) {
727 728 729
		count++;
		g_free (name);
		name = g_strdup_printf (template, count);
730
	}
731 732 733 734 735 736 737

	return name;
}

static GnmFunc *
gnm_func_add_placeholder_full (Workbook *scope,
			       char const *gname, char const *lname,
738
			       char const *type)
739
{
740
	GnmFuncDescriptor desc;
741
	GnmFunc *func;
742
	char const *unknown_cat_name = N_("Unknown Function");
743
	gboolean copy_gname = TRUE;
744
	gboolean copy_lname = TRUE;
745

746 747 748
	g_return_val_if_fail (gname || lname, NULL);
	g_return_val_if_fail (gname == NULL || gnm_func_lookup (gname, scope) == NULL, NULL);
	g_return_val_if_fail (lname == NULL || gnm_func_lookup_localized (lname, scope) == NULL, NULL);
749

750
	if (!unknown_cat)
751 752
		unknown_cat = gnm_func_group_fetch
			(unknown_cat_name, _(unknown_cat_name));
753

754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769
	if (!gname) {
		/*
		 * This is actually a bit of a problem if we don't end up
		 * with a copy of lname (because there already is a function
		 * with that name).  We're likely to save a template name,
		 * but I don't see what else to do.
		 */
		gname = invent_name (lname, functions_by_name, "unknown%d");
		copy_gname = FALSE;
	}
	if (!lname) {
		/* xgettext: This represents a made-up translated function name.  */
		lname = invent_name (gname, functions_by_localized_name, _("unknown%d"));
		copy_lname = FALSE;
	}

770 771
	if (gnm_debug_flag ("func"))
		g_printerr ("Adding placeholder for %s (aka %s)\n", gname, lname);
772

773
	memset (&desc, 0, sizeof (GnmFuncDescriptor));
Morten Welinder's avatar
Morten Welinder committed
774
	desc.name	  = gname;
775 776 777 778
	desc.arg_spec	  = NULL;
	desc.help	  = NULL;
	desc.fn_args	  = NULL;
	desc.fn_nodes	  = &unknownFunctionHandler;
779
	desc.flags	  = GNM_FUNC_IS_PLACEHOLDER;
780 781 782
	desc.impl_status  = GNM_FUNC_IMPL_STATUS_EXISTS;
	desc.test_status  = GNM_FUNC_TEST_STATUS_UNKNOWN;

783 784
	if (scope != NULL)
		desc.flags |= GNM_FUNC_IS_WORKBOOK_LOCAL;
785 786
	else {
#if 0
787
		/* WISHLIST : it would be nice to have a log if these. */
788
		g_warning ("Unknown %s function : %s", type, desc.name);
789 790
#endif
	}
791

792
	func = gnm_func_add (unknown_cat, &desc, NULL);
793

794 795 796 797 798 799
	if (lname) {
		gnm_func_set_localized_name (func, lname);
		if (!copy_lname)
			g_free ((char *)lname);
	}

Morten Welinder's avatar
Morten Welinder committed
800 801 802
	if (!copy_gname)
		g_free ((char *)gname);

803 804 805 806
	if (scope != NULL) {
		if (scope->sheet_local_functions == NULL)
			scope->sheet_local_functions = g_hash_table_new_full (
				g_str_hash, g_str_equal,
807
				NULL, g_object_unref);
808 809 810
		g_hash_table_insert (scope->sheet_local_functions,
			(gpointer)func->name, func);
	}
811 812 813 814

	return func;
}

815 816 817 818 819
/**
 * gnm_func_add_placeholder:
 * @scope: (nullable): scope to defined placeholder, %NULL for global
 * @name: (nullable): function name
 * @type:
820
 *
821
 * Returns: (transfer none): a placeholder with the given name.
822 823 824
 */
GnmFunc *
gnm_func_add_placeholder (Workbook *scope,
825
			  char const *name, char const *type)
826
{
827
	return gnm_func_add_placeholder_full (scope, name, NULL, type);
828 829
}

830 831 832 833 834 835 836
/**
 * gnm_func_add_placeholder_localized:
 * @gname: (nullable): function name
 * @lname: localized function name
 *
 * Returns: (transfer none): a placeholder with the given localized name.
 */
837 838 839
GnmFunc *
gnm_func_add_placeholder_localized (char const *gname, char const *lname)
{
840
	return gnm_func_add_placeholder_full (NULL, gname, lname, "?");
841 842
}

843 844 845 846 847 848 849
/**
 * gnm_func_lookup_or_add_placeholder:
 * @name: function name
 *
 * Returns: (transfer none): a #GnmFunc named @name, either an existing
 * one or a placeholder.
 */
850
GnmFunc	*
851
gnm_func_lookup_or_add_placeholder (char const *name)
852
{
853
	GnmFunc	* f = gnm_func_lookup (name, NULL);
854
	if (f == NULL)
855
		f = gnm_func_add_placeholder (NULL, name, "");
856 857 858
	return f;
}

859 860 861
/**
 * gnm_func_get_name:
 * @func: #GnmFunc to query
862
 * @localized: if %TRUE, use localized name
863 864 865
 *
 * Returns: (transfer none): @func's name
 */
866
char const *
867
gnm_func_get_name (GnmFunc const *func, gboolean localized)
868
{
869
	int i;
870
	GnmFunc *fd = (GnmFunc *)func;
871

872
	g_return_val_if_fail (func != NULL, NULL);
873

874
	if (!localized)
875 876
		return func->name;

877 878 879
	if (func->localized_name)
		return func->localized_name;

880 881 882 883 884 885
	/*
	 * Deduce the translated names from the help texts.  This
	 * code doesn't currently check for clashes in translated
	 * names.
	 */

886
	gnm_func_load_if_stub (fd);
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903

	for (i = 0;
	     (func->localized_name == NULL &&
	      func->help &&
	      func->help[i].type != GNM_FUNC_HELP_END);
	     i++) {
		const char *s, *sl;
		char *U;
		if (func->help[i].type != GNM_FUNC_HELP_NAME)
			continue;

		s = func->help[i].text;
		sl = F2 (func, s);
		if (s == sl) /* String not actually translated. */
			continue;

		U = split_at_colon (F2 (func, s), NULL);
904 905 906 907 908
		if (U) {
			char *lname = g_utf8_strdown (U, -1);
			gnm_func_set_localized_name (fd, lname);
			g_free (lname);
		}
909 910 911
		g_free (U);
	}

912
	if (!func->localized_name)
913
		gnm_func_set_localized_name (fd, fd->name);
914

915
	return func->localized_name;
916 917
}

918 919 920 921
/**
 * gnm_func_get_description:
 * @fn_def: the fn defintion
 *
Morten Welinder's avatar
Morten Welinder committed
922
 * Returns: (transfer none): the description of the function
923
 **/
Morten Welinder's avatar
Morten Welinder committed
924
char const *
925 926 927 928 929 930 931
gnm_func_get_description (GnmFunc const *fn_def)
{
	gint i;
	g_return_val_if_fail (fn_def != NULL, NULL);

	gnm_func_load_if_stub ((GnmFunc *)fn_def);

932 933 934 935 936 937 938 939 940 941 942
	for (i = 0;
	     fn_def->help && fn_def->help[i].type != GNM_FUNC_HELP_END;
	     i++) {
		const char *desc;

		if (fn_def->help[i].type != GNM_FUNC_HELP_NAME)
			continue;

		desc = strchr (F2 (fn_def, fn_def->help[i].text), ':');
		return desc ? (desc + 1) : "";
	}
943 944 945
	return "";
}

946
/**
Morten Welinder's avatar
Morten Welinder committed
947
 * gnm_func_count_args:
948
 * @fn_def: pointer to function definition
Morten Welinder's avatar
Morten Welinder committed
949 950
 * @min: (out): location for mininum args
 * @max: (out): location for mininum args
951
 *
952
 * This calculates the maximum and minimum number of args that can be passed.
Morten Welinder's avatar
Morten Welinder committed
953
 * For a vararg function, the maximum will be set to G_MAXINT.
954
 **/
955
void
Morten Welinder's avatar
Morten Welinder committed
956
gnm_func_count_args (GnmFunc const *fn_def, int *min, int *max)
957 958 959
{
	g_return_if_fail (min != NULL);
	g_return_if_fail (max != NULL);
960 961
	g_return_if_fail (fn_def != NULL);

Morten Welinder's avatar
Morten Welinder committed
962
	gnm_func_load_if_stub ((GnmFunc *)fn_def);
963

Morten Welinder's avatar
Morten Welinder committed
964 965
	*min = fn_def->min_args;
	*max = fn_def->max_args;
966 967 968
}

/**
Morten Welinder's avatar
Morten Welinder committed
969
 * gnm_func_get_arg_type:
970
 * @fn_def: the fn defintion
Morten Welinder's avatar
Morten Welinder committed
971
 * @arg_idx: zero-based argument offset
972
 *
Morten Welinder's avatar
Morten Welinder committed
973
 * Returns: the type of the argument
974
 **/
975
char
Morten Welinder's avatar
Morten Welinder committed
976
gnm_func_get_arg_type (GnmFunc const *fn_def, int arg_idx)
977
{
978
	g_return_val_if_fail (fn_def != NULL, '?');
979

Morten Welinder's avatar
Morten Welinder committed
980
	gnm_func_load_if_stub ((GnmFunc *)fn_def);
981

Morten Welinder's avatar
Morten Welinder committed
982
	g_return_val_if_fail (arg_idx >= 0 && arg_idx < fn_def->max_args, '?');
983

Morten Welinder's avatar
Morten Welinder committed
984
	return fn_def->arg_types ? fn_def->arg_types[arg_idx] : '?';
985 986
}

987
/**
Morten Welinder's avatar
Morten Welinder committed
988
 * gnm_func_get_arg_type_string:
989
 * @fn_def: the fn defintion
Morten Welinder's avatar
Morten Welinder committed
990
 * @arg_idx: zero-based argument offset
991
 *
Morten Welinder's avatar
Morten Welinder committed
992
 * Return value: (transfer none): the type of the argument as a string
993 994
 **/
char const *
Morten Welinder's avatar
Morten Welinder committed
995
gnm_func_get_arg_type_string (GnmFunc const *fn_def,
996
			      int arg_idx)
997
{
Morten Welinder's avatar
Morten Welinder committed
998
	switch (gnm_func_get_arg_type (fn_def, arg_idx)) {
999 1000 1001 1002 1003 1004 1005 1006 1007 1008
	case 'f':
		return _("Number");
	case 's':
		return _("String");
	case 'b':
		return _("Boolean");
	case 'r':
		return _("Cell Range");
	case 'A':
		return _("Area");
Jody Goldberg's avatar
Jody Goldberg committed
1009
	case 'E':
1010
		return _("Scalar, Blank, or Error");
1011 1012
	case 'S':
		return _("Scalar");
1013
	case '?':
1014
		/* Missing values will be NULL.  */
1015
		return _("Any");
1016 1017

	default:
Jeremy Bicha's avatar
Jeremy Bicha committed
1018
		g_warning ("Unknown arg type");
1019
		return "Broken";
1020 1021 1022 1023
	}
}

/**
Morten Welinder's avatar
Morten Welinder committed
1024
 * gnm_func_get_arg_name:
Morten Welinder's avatar
Morten Welinder committed
1025 1026
 * @func: #GnmFunc
 * @arg_idx: zero-based argument offset
1027
 *
Morten Welinder's avatar
Morten Welinder committed
1028
 * Returns: (transfer full) (nullable): the name of the argument
1029
 **/
1030
char *
Morten Welinder's avatar
Morten Welinder committed
1031
gnm_func_get_arg_name (GnmFunc const *func, guint arg_idx)
1032
{
Morten Welinder's avatar
Morten Welinder committed
1033
	g_return_val_if_fail (func != NULL, NULL);
1034

Morten Welinder's avatar
Morten Welinder committed
1035
	gnm_func_load_if_stub ((GnmFunc *)func);
1036

Morten Welinder's avatar
Morten Welinder committed
1037 1038
	if (func->arg_names && arg_idx < func->arg_names->len)
		return g_strdup (g_ptr_array_index (func->arg_names, arg_idx));
1039
	return NULL;
1040 1041
}

1042 1043 1044
/**
 * gnm_func_get_arg_description:
 * @fn_def: the fn defintion
Morten Welinder's avatar
Morten Welinder committed
1045
 * @arg_idx: zero-based argument offset
1046
 *
Morten Welinder's avatar
Morten Welinder committed
1047
 * Returns: (transfer none): the description of the argument
1048 1049 1050 1051 1052 1053 1054 1055 1056
 **/
char const*
gnm_func_get_arg_description (GnmFunc const *fn_def, guint arg_idx)
{
	gint i;
	g_return_val_if_fail (fn_def != NULL, NULL);

	gnm_func_load_if_stub ((GnmFunc *)fn_def);

1057 1058 1059 1060 1061 1062 1063
	for (i = 0;
	     fn_def->help && fn_def->help[i].type != GNM_FUNC_HELP_END;
	     i++) {
		gchar const *desc;

		if (fn_def->help[i].type != GNM_FUNC_HELP_ARG)
			continue;
1064
		if (arg_idx--)
1065 1066 1067
			continue;

		desc = strchr (F2 (fn_def, fn_def->help[i].text), ':');
1068 1069 1070 1071 1072 1073 1074
		if (!desc)
			return "";

		desc++;
		while (g_unichar_isspace (g_utf8_get_char (desc)))
			desc = g_utf8_next_char (desc);
		return desc;
1075
	}
1076 1077 1078 1079

	return "";
}

1080 1081 1082
/**
 * gnm_func_convert_markup_to_pango:
 * @desc: the fn or arg description string
1083
 * @target: target widget for the markup.
1084 1085 1086 1087 1088
 *
 * Return value: the escaped string with @{} markup converted to
 *               pango markup
 **/
char *
1089
gnm_func_convert_markup_to_pango (char const *desc, GtkWidget *target)
1090 1091 1092
{
	GString *str;
	gchar *markup, *at;
Morten Welinder's avatar
Morten Welinder committed
1093 1094
	GdkRGBA link_color;
	PangoColor pg;
1095 1096 1097
	char *link_color_text, *span_text;
	size_t span_text_len;

Morten Welinder's avatar
Morten Welinder committed
1098 1099 1100 1101 1102
	gnm_get_link_color (target, &link_color);
	pg.red = 65535 * link_color.red;
	pg.green = 65535 * link_color.green;
	pg.blue = 65535 * link_color.blue;
	link_color_text = pango_color_to_string (&pg);
1103 1104 1105 1106
	span_text = g_strdup_printf ("<span foreground=\"%s\">",
				     link_color_text);
	span_text_len = strlen (span_text);
	g_free (link_color_text);
1107 1108 1109 1110 1111 1112 1113

	markup = g_markup_escape_text (desc, -1);
	str = g_string_new (markup);
	g_free (markup);

	while ((at = strstr (str->str, "@{"))) {
		gint len = at - str->str;
1114
		go_string_replace (str, len, 2, span_text, -1);
1115
		if ((at = strstr
1116
		     (str->str + len + span_text_len, "}"))) {
1117
			len = at - str->str;
1118
			go_string_replace (str, len, 1, "</span>", -1);
1119 1120
		} else
			g_string_append (str, "</span>");
1121
	}
1122
	g_free (span_text);
1123 1124 1125 1126

	return g_string_free (str, FALSE);
}

1127

1128 1129
/* ------------------------------------------------------------------------- */

Jody Goldberg's avatar
Jody Goldberg committed
1130
static inline void
Jody Goldberg's avatar
Jody Goldberg committed
1131
free_values (GnmValue **values, int top)
Jody Goldberg's avatar
Jody Goldberg committed
1132 1133 1134 1135 1136 1137 1138 1139
{
	int i;

	for (i = 0; i < top; i++)
		if (values [i])
			value_release (values [i]);
}

1140 1141
/* ------------------------------------------------------------------------- */

1142
/**
1143
 * function_call_with_exprs:
1144
 * @ei: EvalInfo containing valid fn_def!
1145
 *
1146
 * Do the guts of calling a function.
1147
 *
1148
 * Returns the result.
1149
 **/
Jody Goldberg's avatar
Jody Goldberg committed
1150
GnmValue *
1151
function_call_with_exprs (GnmFuncEvalInfo *ei)
1152
{
1153
	GnmFunc const *fn_def;
1154
	int	  i, iter_count, iter_width = 0, iter_height = 0;
1155
	char	  arg_type;
Jody Goldberg's avatar
Jody Goldberg committed
1156
	GnmValue	 **args, *tmp = NULL;
1157
	int	 *iter_item = NULL;
1158 1159
	int argc;
	GnmExprConstPtr *argv;
1160
	GnmExprEvalFlags flags, pass_flags;
1161 1162

	g_return_val_if_fail (ei != NULL, NULL);
1163
	g_return_val_if_fail (ei->func_call != NULL, NULL);
1164

1165 1166
	flags = ei->flags;

1167 1168
	argc = ei->func_call->argc;
	argv = ei->func_call->argv;
1169
	fn_def = ei->func_call->func;
Morten Welinder's avatar
Morten Welinder committed
1170

1171 1172
	gnm_func_load_if_stub ((GnmFunc *)fn_def);

1173
	/* Functions that deal with ExprNodes */
1174
	if (fn_def->fn_type == GNM_FUNC_TYPE_NODES)
Morten Welinder's avatar
Morten Welinder committed
1175
		return fn_def->nodes_func (ei, argc, argv);
1176

1177
	/* Functions that take pre-computed Values */
1178 1179
	if (argc > fn_def->max_args ||
	    argc < fn_def->min_args)
1180
		return value_new_error_NA (ei->pos);
1181

1182
	args = g_alloca (sizeof (GnmValue *) * fn_def->max_args);
1183
	iter_count = (eval_pos_is_array_context (ei->pos) &&
1184 1185
		      (flags & GNM_EXPR_EVAL_PERMIT_NON_SCALAR))
		? 0 : -1;
1186

1187
	/* Optimization for IF when implicit iteration is not used.  */
Morten Welinder's avatar
Morten Welinder committed
1188
	if (ei->func_call->func->args_func == gnumeric_if &&
1189
	    iter_count == -1)
1190
		return gnumeric_if2 (ei, argc, argv, flags);
1191

1192 1193 1194
	pass_flags = (flags &
		      (GNM_EXPR_EVAL_ARRAY_CONTEXT));

1195
	for (i = 0; i < argc; i++) {
1196
		char arg_type = fn_def->arg_types[i];
1197 1198
		/* expr is always non-null, missing args are encoded as
		 * const = empty */
1199
		GnmExpr const *expr = argv[i];
1200 1201

		if (arg_type == 'A' || arg_type == 'r') {
1202 1203
			tmp = args[i] = gnm_expr_eval
				(expr, ei->pos,
1204
				 pass_flags |
1205 1206 1207 1208 1209 1210
				 GNM_EXPR_EVAL_PERMIT_NON_SCALAR |
				 GNM_EXPR_EVAL_WANT_REF);
			if (VALUE_IS_ERROR (tmp)) {
				free_values (args, i);
				return tmp;
			}
1211

1212
			if (VALUE_IS_CELLRANGE (tmp)) {
1213 1214 1215 1216 1217 1218
				gnm_cellref_make_abs (&tmp->v_range.cell.a,
						      &tmp->v_range.cell.a,
						      ei->pos);
				gnm_cellref_make_abs (&tmp->v_range.cell.b,
						      &tmp->v_range.cell.b,
						      ei->pos);
1219
				/* Array args accept scalars */
1220
			} else if (arg_type != 'A' && !VALUE_IS_ARRAY (tmp)) {
1221 1222
				free_values (args, i + 1);
				return value_new_error_VALUE (ei->pos);
1223 1224 1225
			}
			continue;
		}
1226

1227
		/* force scalars whenever we are certain */
1228 1229 1230 1231 1232 1233 1234
		tmp = args[i] = gnm_expr_eval
			(expr, ei->pos,
			 pass_flags |
			 GNM_EXPR_EVAL_PERMIT_EMPTY |
			 (iter_count >= 0 || arg_type == '?'
			  ? GNM_EXPR_EVAL_PERMIT_NON_SCALAR
			  : 0));
1235

1236
		if (arg_type == '?')	/* '?' arguments are unrestriced */
1237
			continue;
1238 1239

		/* optional arguments can be blank */
1240
		if (i >= fn_def->min_args && VALUE_IS_EMPTY (tmp)) {
1241 1242 1243 1244 1245 1246
			if (arg_type == 'E' && !gnm_expr_is_empty (expr)) {
				/* An actual argument produced empty.  Make
				   sure function sees that.  */
				args[i] = value_new_empty ();
			}

1247
			continue;
1248
		}
1249

1250 1251
		if (tmp == NULL)
			tmp = args[i] = value_new_empty ();
1252

1253
		/* Handle implicit intersection or iteration depending on flags */
1254
		if (VALUE_IS_CELLRANGE (tmp) || VALUE_IS_ARRAY (tmp)) {
Jody Goldberg's avatar
Jody Goldberg committed
1255 1256 1257 1258
			if (iter_count > 0) {
				if (iter_width != value_area_get_width (tmp, ei->pos) ||
				    iter_height != value_area_get_height (tmp, ei->pos)) {
					free_values (args, i + 1);
1259
					return value_new_error_VALUE (ei->pos);
1260 1261
				}
			} else {
Jody Goldberg's avatar
Jody Goldberg committed
1262
				if (iter_count < 0) {
1263
					g_warning ("Damn I thought this was impossible");
Jody Goldberg's avatar
Jody Goldberg committed
1264
					iter_count = 0;
1265
				}
Jody Goldberg's avatar
Jody Goldberg committed
1266 1267 1268
				iter_item = g_alloca (sizeof (int) * argc);
				iter_width = value_area_get_width (tmp, ei->pos);
				iter_height = value_area_get_height (tmp, ei->pos);
1269
			}
1270 1271 1272 1273
			iter_item [iter_count++] = i;

			/* no need to check type, we would fail comparing a range against a "b, f, or s" */
			continue;
1274 1275 1276
		}

		/* All of these argument types must be scalars */
1277 1278
		switch (arg_type) {
		case 'b':
1279
			if (VALUE_IS_STRING (tmp)) {
1280
				gboolean err;
1281
				gboolean b = value_get_as_bool (tmp, &err);
1282 1283 1284 1285 1286 1287 1288 1289 1290
				if (err) {
					free_values (args, i + 1);
					return value_new_error_VALUE (ei->pos);
				}
				value_release (args[i]);
				tmp = args[i] = value_new_bool (b);
				break;
			}
			/* Fall through.  */
1291
		case 'f':
1292
			if (VALUE_IS_STRING (tmp)) {
1293
				tmp = format_match_number (value_peek_string (tmp), NULL,
1294
					sheet_date_conv (ei->pos->sheet));
1295 1296
				if (tmp == NULL) {
					free_values (args, i + 1);
1297
					return value_new_error_VALUE (ei->pos);
Jody Goldberg's avatar