Updated Czech translation
[gnumeric.git] / src / func.c
blobfebb34f762b2f8e4043985b89e67a2e11633349d
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /*
4 * func.c: Function management and utility routines.
6 * Author:
7 * Miguel de Icaza (miguel@gnu.org)
8 * Michael Meeks (mmeeks@gnu.org)
9 * Morten Welinder (terra@gnome.org)
10 * Jody Goldberg (jody@gnome.org)
12 #include <gnumeric-config.h>
13 #include <glib/gi18n-lib.h>
14 #include <glib/gstdio.h>
15 #include "gnumeric.h"
16 #include "func.h"
18 #include "parse-util.h"
19 #include "dependent.h"
20 #include "expr.h"
21 #include "expr-impl.h"
22 #include "expr-name.h"
23 #include "cell.h"
24 #include "workbook-priv.h"
25 #include "sheet.h"
26 #include "value.h"
27 #include "number-match.h"
28 #include "func-builtin.h"
29 #include "command-context-stderr.h"
30 #include "gnm-plugin.h"
31 #include "gutils.h"
33 #include <goffice/goffice.h>
34 #include <glib.h>
35 #include <string.h>
36 #include <stdlib.h>
38 #define UNICODE_ELLIPSIS "\xe2\x80\xa6"
39 #define F2(func,s) dgettext ((func)->textdomain->str, (s))
41 static GList *categories;
42 static GnmFuncGroup *unknown_cat;
44 static GHashTable *functions_by_name;
45 static GHashTable *functions_by_localized_name;
47 void
48 functions_init (void)
50 functions_by_name =
51 g_hash_table_new (go_ascii_strcase_hash, go_ascii_strcase_equal);
53 /* FIXME: ascii??? */
54 functions_by_localized_name =
55 g_hash_table_new (go_ascii_strcase_hash, go_ascii_strcase_equal);
57 func_builtin_init ();
60 void
61 functions_shutdown (void)
63 while (unknown_cat != NULL && unknown_cat->functions != NULL) {
64 GnmFunc *func = unknown_cat->functions->data;
65 if (func->usage_count > 0) {
66 g_warning ("Function %s still has %d users.\n",
67 gnm_func_get_name (func, FALSE),
68 func->usage_count);
69 func->usage_count = 0;
71 gnm_func_free (func);
73 func_builtin_shutdown ();
75 g_hash_table_destroy (functions_by_name);
76 functions_by_name = NULL;
78 g_hash_table_destroy (functions_by_localized_name);
79 functions_by_localized_name = NULL;
82 inline void
83 gnm_func_load_if_stub (GnmFunc *func)
85 if (func->fn_type == GNM_FUNC_TYPE_STUB)
86 gnm_func_load_stub (func);
89 static void
90 copy_hash_table_to_ptr_array (gpointer key, gpointer value, gpointer array)
92 GnmFunc *fd = value;
94 if (fd->name == NULL ||
95 strcmp (fd->name, "perl_adder") == 0 ||
96 strcmp (fd->name, "perl_date") == 0 ||
97 strcmp (fd->name, "perl_sed") == 0 ||
98 strcmp (fd->name, "py_capwords") == 0 ||
99 strcmp (fd->name, "py_printf") == 0 ||
100 strcmp (fd->name, "py_bitand") == 0)
101 return;
103 gnm_func_load_if_stub (fd);
104 if (fd->help != NULL)
105 g_ptr_array_add (array, fd);
108 static int
109 func_def_cmp (gconstpointer a, gconstpointer b)
111 GnmFunc const *fda = *(GnmFunc const **)a ;
112 GnmFunc const *fdb = *(GnmFunc const **)b ;
114 g_return_val_if_fail (fda->name != NULL, 0);
115 g_return_val_if_fail (fdb->name != NULL, 0);
117 if (fda->fn_group != NULL && fdb->fn_group != NULL) {
118 int res = go_string_cmp (fda->fn_group->display_name,
119 fdb->fn_group->display_name);
120 if (res != 0)
121 return res;
124 return g_ascii_strcasecmp (fda->name, fdb->name);
127 static void
128 cb_dump_usage (gpointer key, GnmFunc const *fd, FILE *out)
130 if (fd->usage_count > 0)
131 fprintf (out, "%d,%s\n", fd->usage_count, fd->name);
134 static char *
135 split_at_colon (char const *s, char **rest)
137 char *dup = g_strdup (s);
138 char *colon = strchr (dup, ':');
139 if (colon) {
140 *colon = 0;
141 if (rest) *rest = colon + 1;
142 } else {
143 if (rest) *rest = NULL;
145 return dup;
148 static void
149 dump_externals (GPtrArray *defs, FILE *out)
151 unsigned int ui;
153 fprintf (out, "<!--#set var=\"title\" value=\"Gnumeric Web Documentation\" -->");
154 fprintf (out, "<!--#set var=\"rootdir\" value=\".\" -->");
155 fprintf (out, "<!--#include virtual=\"header-begin.shtml\" -->");
156 fprintf (out, "<link rel=\"stylesheet\" href=\"style/index.css\" type=\"text/css\"/>");
157 fprintf (out, "<!--#include virtual=\"header-end.shtml\" -->");
158 fprintf (out, "<!--#set var=\"wolfram\" value=\"none\" -->");
159 fprintf (out, "<!--#set var=\"wiki\" value=\"none\" -->");
160 fprintf (out, "<!--\n\n-->");
162 for (ui = 0; ui < defs->len; ui++) {
163 GnmFunc const *fd = g_ptr_array_index (defs, ui);
164 gboolean any = FALSE;
165 int j;
167 for (j = 0; fd->help[j].type != GNM_FUNC_HELP_END; j++) {
168 const char *s = F2(fd, fd->help[j].text);
170 switch (fd->help[j].type) {
171 case GNM_FUNC_HELP_EXTREF:
172 if (!any) {
173 any = TRUE;
174 fprintf (out, "<!--#if expr=\"${QUERY_STRING} = %s\" -->", fd->name);
177 if (strncmp (s, "wolfram:", 8) == 0) {
178 fprintf (out, "<!--#set var=\"wolfram\" value=\"%s\" -->", s + 8);
180 if (strncmp (s, "wiki:", 5) == 0) {
181 char *lang, *page;
182 lang = split_at_colon (s + 5, &page);
183 fprintf (out, "<!--#set var=\"wiki_lang\" value=\"%s\" -->", lang);
184 fprintf (out, "<!--#set var=\"wiki\" value=\"%s\" -->", page);
185 g_free (lang);
187 break;
188 default:
189 break;
193 if (any)
194 fprintf (out, "<!--#endif\n\n-->");
197 fprintf (out, "<div class=\"floatflush\">\n");
198 fprintf (out, "<h1>Online Documentation for \"<!--#echo var=\"QUERY_STRING\" -->\"</h1>\n");
199 fprintf (out, "<p>When last checked, these sources provided useful information about\n");
200 fprintf (out, "this function. However, since the links are not controlled by the\n");
201 fprintf (out, "Gnumeric Team, we cannot guarantee that the links still work. If\n");
202 fprintf (out, "you find that they do not work, please drop us a line.</p>\n");
203 fprintf (out, "<ul>");
204 fprintf (out, "<!--#if expr=\"${wolfram} != none\"-->");
205 fprintf (out, "<li><a href=\"http://mathworld.wolfram.com/<!--#echo var=\"wolfram\" -->\">Wolfram Mathworld\nentry</a>.</li><!--#endif-->");
206 fprintf (out, "<!--#if expr=\"${wiki} != none\"--><li><a href=\"http://<!--#echo var=\"wiki_lang\" -->.wikipedia.org/wiki/<!--#echo var=\"wiki\" -->\">Wikipedia\nentry</a>.</li><!--#endif-->");
207 fprintf (out, "<li><a href=\"http://www.google.com/#q=<!--#echo var=\"QUERY_STRING\" -->\">Google Search</a>.</li>");
208 fprintf (out, "</ul>");
209 fprintf (out, "</div>\n");
211 fprintf (out, "<!--#include virtual=\"footer.shtml\" -->\n");
215 * function_dump_defs :
216 * @filename:
217 * @dump_type:
219 * A generic utility routine to operate on all funtion defs
220 * in various ways. @dump_type will change/extend as needed
221 * Right now
222 * 0 : www.gnumeric.org's function.shtml page
223 * 1 :
224 * 2 : generate_po
225 * 3 : dump function usage count
226 * 4 : external refs
228 void
229 function_dump_defs (char const *filename, int dump_type)
231 FILE *output_file;
232 char *up, *catname;
233 unsigned i;
234 GPtrArray *ordered;
235 GnmFuncGroup const *group = NULL;
237 if (dump_type == 2) {
238 g_printerr ("generate po is obsolete.\n");
239 return;
241 g_return_if_fail (filename != NULL);
243 if ((output_file = g_fopen (filename, "w")) == NULL){
244 g_printerr (_("Cannot create file %s\n"), filename);
245 exit (1);
248 if (dump_type == 3) {
249 g_hash_table_foreach (functions_by_name,
250 (GHFunc) cb_dump_usage,
251 output_file);
252 fclose (output_file);
253 return;
256 /* TODO : Use the translated names and split by fn_group. */
257 ordered = g_ptr_array_new ();
258 g_hash_table_foreach (functions_by_name,
259 copy_hash_table_to_ptr_array, ordered);
261 if (ordered->len > 0)
262 qsort (&g_ptr_array_index (ordered, 0),
263 ordered->len, sizeof (gpointer),
264 func_def_cmp);
266 if (dump_type == 4) {
267 dump_externals (ordered, output_file);
268 g_ptr_array_free (ordered, TRUE);
269 fclose (output_file);
270 return;
273 if (dump_type == 0) {
274 int unique = 0;
275 for (i = 0; i < ordered->len; i++) {
276 GnmFunc const *fd = g_ptr_array_index (ordered, i);
277 switch (fd->impl_status) {
278 case GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC:
279 unique++;
280 break;
281 default: ;
285 fprintf (output_file,
286 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
287 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
288 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
289 "<!-- DEFINE current=Home -->\n"
290 "<!-- MARKER: start-header -->\n"
291 "<head>\n"
292 "<title>Gnumeric</title>\n"
293 "<link rel=\"stylesheet\" href=\"style/style.css\" type=\"text/css\" />\n"
294 "<link rel=\"icon\" type=\"image/png\" href=\"logo.png\" />\n"
295 "<style type=\"text/css\"><!--\n"
296 " div.functiongroup {\n"
297 " margin-top: 1em;\n"
298 " margin-bottom: 1em;\n"
299 " }\n"
300 " table.functiongroup {\n"
301 " border-style: solid;\n"
302 " border-width: 1px;\n"
303 " border-spacing: 0px;\n"
304 " }\n"
305 " tr.header td {\n"
306 " font-weight: bold;\n"
307 " font-size: 14pt;\n"
308 " border-style: solid;\n"
309 " border-width: 1px;\n"
310 " text-align: center;\n"
311 " }\n"
312 " tr.function td {\n"
313 " border: solid 1px;\n"
314 " }\n"
315 " td.testing-unknown { background: #ffffff; }\n"
316 " td.testing-nosuite { background: #ff7662; }\n"
317 " td.testing-basic { background: #fff79d; }\n"
318 " td.testing-exhaustive { background: #aef8b5; }\n"
319 " td.testing-devel { background: #ff6c00; }\n"
320 " td.imp-exists { background: #ffffff; }\n"
321 " td.imp-no { background: #ff7662; }\n"
322 " td.imp-subset { background: #fff79d; }\n"
323 " td.imp-complete { background: #aef8b5; }\n"
324 " td.imp-superset { background: #16e49e; }\n"
325 " td.imp-subsetext { background: #59fff2; }\n"
326 " td.imp-devel { background: #ff6c00; }\n"
327 " td.imp-gnumeric { background: #44be18; }\n"
328 "--></style>\n"
329 "</head>\n"
330 "<body>\n"
331 "<div id=\"wrap\">\n"
332 " <a href=\"/\"><div id=\"header\">\n"
333 " <h1 id=\"logo-text\"><span>Gnumeric</span></h1>\n"
334 " <p id=\"slogan\">Free, Fast, Accurate &mdash; Pick Any Three!</p>\n"
335 " <img id=\"logo\" src=\"gnumeric.png\" alt=\"logo\" class=\"float-right\"/>\n"
336 " </div></a>\n"
337 "\n"
338 " <div id=\"nav\">\n"
339 " <ul>\n"
340 " <li id=\"current\"><a href=\"/\">Home</a></li>\n"
341 " <li><a href=\"development.html\">Development</a></li>\n"
342 " <li><a href=\"contact.html\">Contact</a></li>\n"
343 " </ul>\n"
344 " </div>\n"
345 "\n"
346 " <div id=\"content-wrap\">\n"
347 " <!-- MARKER: start-main -->\n"
348 " <div id=\"main\">\n"
349 " <div class=\"generalitem\">\n"
350 " <h2><span class=\"gnumeric-bullet\"></span>Gnumeric Sheet Functions</h2>\n"
351 " <p>Gnumeric currently has %d functions for use in spreadsheets.\n"
352 " %d of these are unique to Gnumeric.</p>\n",
353 ordered->len, unique);
356 for (i = 0; i < ordered->len; i++) {
357 GnmFunc const *fd = g_ptr_array_index (ordered, i);
358 if (dump_type == 1) {
359 int i;
360 gboolean first_arg = TRUE;
361 GString *syntax = g_string_new (NULL);
362 GString *arg_desc = g_string_new (NULL);
363 GString *desc = g_string_new (NULL);
364 GString *odf = g_string_new (NULL);
365 GString *excel = g_string_new (NULL);
366 GString *note = g_string_new (NULL);
367 GString *seealso = g_string_new (NULL);
368 gint min, max;
370 fprintf (output_file, "@CATEGORY=%s\n",
371 F2(fd, fd->fn_group->display_name->str));
372 for (i = 0;
373 fd->help[i].type != GNM_FUNC_HELP_END;
374 i++) {
375 switch (fd->help[i].type) {
376 case GNM_FUNC_HELP_NAME: {
377 char *short_desc;
378 char *name = split_at_colon (F2(fd, fd->help[i].text), &short_desc);
379 fprintf (output_file,
380 "@FUNCTION=%s\n",
381 name);
382 fprintf (output_file,
383 "@SHORTDESC=%s\n",
384 short_desc);
385 g_string_append (syntax, name);
386 g_string_append_c (syntax, '(');
387 g_free (name);
388 break;
390 case GNM_FUNC_HELP_SEEALSO:
391 if (seealso->len > 0)
392 g_string_append (seealso, ",");
393 g_string_append (seealso, F2(fd, fd->help[i].text));
394 break;
395 case GNM_FUNC_HELP_DESCRIPTION:
396 if (desc->len > 0)
397 g_string_append (desc, "\n");
398 g_string_append (desc, F2(fd, fd->help[i].text));
399 break;
400 case GNM_FUNC_HELP_NOTE:
401 if (note->len > 0)
402 g_string_append (note, " ");
403 g_string_append (note, F2(fd, fd->help[i].text));
404 break;
405 case GNM_FUNC_HELP_ARG: {
406 char *argdesc;
407 char *name = split_at_colon (F2(fd, fd->help[i].text), &argdesc);
408 if (first_arg)
409 first_arg = FALSE;
410 else
411 g_string_append_c (syntax, go_locale_get_arg_sep ());
412 g_string_append (syntax, name);
413 if (argdesc) {
414 g_string_append_printf (arg_desc,
415 "@{%s}: %s\n",
416 name,
417 argdesc);
419 g_free (name);
420 /* FIXME: Optional args? */
421 break;
423 case GNM_FUNC_HELP_ODF:
424 if (odf->len > 0)
425 g_string_append (odf, " ");
426 g_string_append (odf, F2(fd, fd->help[i].text));
427 break;
428 case GNM_FUNC_HELP_EXCEL:
429 if (excel->len > 0)
430 g_string_append (excel, " ");
431 g_string_append (excel, F2(fd, fd->help[i].text));
432 break;
434 case GNM_FUNC_HELP_EXTREF:
435 /* FIXME! */
436 case GNM_FUNC_HELP_EXAMPLES:
437 /* FIXME! */
438 case GNM_FUNC_HELP_END:
439 break;
443 function_def_count_args (fd, &min, &max);
444 if (max == G_MAXINT)
445 fprintf (output_file,
446 "@SYNTAX=%s," UNICODE_ELLIPSIS ")\n",
447 syntax->str);
448 else
449 fprintf (output_file, "@SYNTAX=%s)\n",
450 syntax->str);
452 if (arg_desc->len > 0)
453 fprintf (output_file, "@ARGUMENTDESCRIPTION=%s", arg_desc->str);
454 if (desc->len > 0)
455 fprintf (output_file, "@DESCRIPTION=%s\n", desc->str);
456 if (note->len > 0)
457 fprintf (output_file, "@NOTE=%s\n", note->str);
458 if (excel->len > 0)
459 fprintf (output_file, "@EXCEL=%s\n", excel->str);
460 if (odf->len > 0)
461 fprintf (output_file, "@ODF=%s\n", odf->str);
462 if (seealso->len > 0)
463 fprintf (output_file, "@SEEALSO=%s\n", seealso->str);
465 g_string_free (syntax, TRUE);
466 g_string_free (arg_desc, TRUE);
467 g_string_free (desc, TRUE);
468 g_string_free (odf, TRUE);
469 g_string_free (excel, TRUE);
470 g_string_free (note, TRUE);
471 g_string_free (seealso, TRUE);
473 fputc ('\n', output_file);
474 } else if (dump_type == 0) {
475 static struct {
476 char const *name;
477 char const *klass;
478 } const testing [] = {
479 { "Unknown", "testing-unknown" },
480 { "No Testsuite", "testing-nosuite" },
481 { "Basic", "testing-basic" },
482 { "Exhaustive", "testing-exhaustive" },
483 { "Under Development", "testing-devel" }
485 static struct {
486 char const *name;
487 char const *klass;
488 } const implementation [] = {
489 { "Exists", "imp-exists" },
490 { "Unimplemented", "imp-no" },
491 { "Subset", "imp-subset" },
492 { "Complete", "imp-complete" },
493 { "Superset", "imp-superset" },
494 { "Subset with_extensions", "imp-subsetext" },
495 { "Under development", "imp-devel" },
496 { "Unique to Gnumeric", "imp-gnumeric" },
498 if (group != fd->fn_group) {
499 if (group) fprintf (output_file, "</table></div>\n");
500 group = fd->fn_group;
501 fprintf (output_file,
502 "<h2>%s</h2>\n"
503 "<div class=\"functiongroup\"><table class=\"functiongroup\">\n"
504 "<tr class=\"header\">"
505 "<td>Function</td>"
506 "<td>Implementation</td>"
507 "<td>Testing</td>"
508 "</tr>\n",
509 group->display_name->str);
511 up = g_ascii_strup (fd->name, -1);
512 catname = g_strdup (group->display_name->str);
513 while (strchr (catname, ' '))
514 *strchr (catname, ' ') = '_';
515 fprintf (output_file, "<tr class=\"function\">\n");
516 fprintf (output_file,
517 "<td><a href =\"https://help.gnome.org/users/gnumeric/stable/CATEGORY_%s.html.en#gnumeric-function-%s\">%s</a></td>\n",
518 catname, up, fd->name);
519 g_free (up);
520 g_free (catname);
521 fprintf (output_file,
522 "<td class=\"%s\"><a href=\"mailto:gnumeric-list@gnome.org?subject=Re: %s implementation\">%s</a></td>\n",
523 implementation[fd->impl_status].klass,
524 fd->name,
525 implementation[fd->impl_status].name);
526 fprintf (output_file,
527 "<td class=\"%s\"><a href=\"mailto:gnumeric-list@gnome.org?subject=Re: %s testing\">%s</a></td>\n",
528 testing[fd->test_status].klass,
529 fd->name,
530 testing[fd->test_status].name);
531 fprintf (output_file,"</tr>\n");
534 if (dump_type == 0) {
535 if (group) fprintf (output_file, "</table></div>\n");
536 fprintf (output_file,
537 " </div>\n"
538 " </div>\n"
539 " <!-- MARKER: end-main -->\n"
540 " <!-- MARKER: start-sidebar -->\n"
541 " <!-- MARKER: end-sidebar -->\n"
542 " </div>\n"
543 "</div>\n"
544 "</body>\n"
545 "</html>\n");
548 g_ptr_array_free (ordered, TRUE);
549 fclose (output_file);
552 /* ------------------------------------------------------------------------- */
554 static gboolean
555 check_help_expression (const char *text, GnmFunc const *fd)
557 GnmConventions const *convs = gnm_conventions_default;
558 GnmParsePos pp;
559 GnmExprTop const *texpr;
560 Workbook *wb;
561 GnmParseError perr;
563 /* Create a dummy workbook with no sheets for interesting effects. */
564 wb = workbook_new ();
565 parse_pos_init (&pp, wb, NULL, 0, 0);
567 parse_error_init (&perr);
569 texpr = gnm_expr_parse_str (text, &pp,
570 GNM_EXPR_PARSE_DEFAULT,
571 convs,
572 &perr);
573 if (perr.err) {
574 g_printerr ("Error parsing %s: %s\n",
575 text, perr.err->message);
577 parse_error_free (&perr);
578 g_object_unref (wb);
580 if (!texpr)
581 return TRUE;
583 gnm_expr_top_unref (texpr);
584 return FALSE;
587 static gboolean
588 check_argument_refs (const char *text, GnmFunc const *fd)
590 if (fd->fn_type != GNM_FUNC_TYPE_ARGS)
591 return FALSE;
593 while (1) {
594 const char *at = strchr (text, '@');
595 char *argname;
596 int i;
598 if (!at)
599 return FALSE;
600 if (at[1] != '{')
601 return TRUE;
602 text = strchr (at + 2, '}');
603 if (!text)
604 return FALSE;
605 argname = g_strndup (at + 2, text - at - 2);
607 for (i = 0; TRUE; i++) {
608 char *thisarg = function_def_get_arg_name (fd, i);
609 gboolean found;
610 if (!thisarg) {
611 g_free (argname);
612 return TRUE;
614 found = strcmp (argname, thisarg) == 0;
615 g_free (thisarg);
616 if (found)
617 break;
619 g_free (argname);
624 static int
625 gnm_func_sanity_check1 (GnmFunc const *fd)
627 GnmFuncHelp const *h;
628 int counts[(int)GNM_FUNC_HELP_ODF + 1];
629 int res = 0;
630 size_t nlen = strlen (fd->name);
631 GHashTable *allargs;
633 allargs = g_hash_table_new_full
634 (g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL);
636 memset (counts, 0, sizeof (counts));
637 for (h = fd->help; h->type != GNM_FUNC_HELP_END; h++) {
638 g_assert (h->type <= GNM_FUNC_HELP_ODF);
639 counts[h->type]++;
641 if (!g_utf8_validate (h->text, -1, NULL)) {
642 g_printerr ("%s: Invalid UTF-8 in type %i\n",
643 fd->name, h->type);
644 res = 1;
645 continue;
648 switch (h->type) {
649 case GNM_FUNC_HELP_NAME:
650 if (g_ascii_strncasecmp (fd->name, h->text, nlen) ||
651 h->text[nlen] != ':') {
652 g_printerr ("%s: Invalid NAME record\n",
653 fd->name);
654 res = 1;
655 } else if (h->text[nlen + 1] == ' ') {
656 g_printerr ("%s: Unwanted space in NAME record\n",
657 fd->name);
658 res = 1;
659 } else if (h->text[strlen (h->text) - 1] == '.') {
660 g_printerr ("%s: Unwanted period in NAME record\n",
661 fd->name);
662 res = 1;
664 break;
665 case GNM_FUNC_HELP_ARG: {
666 const char *aend = strchr (h->text, ':');
667 char *argname;
669 if (aend == NULL || aend == h->text) {
670 g_printerr ("%s: Invalid ARG record\n",
671 fd->name);
672 res = 1;
673 break;
676 if (aend[1] == ' ') {
677 g_printerr ("%s: Unwanted space in ARG record\n",
678 fd->name);
679 res = 1;
681 if (aend[1] == '\0') {
682 g_printerr ("%s: Empty ARG record\n",
683 fd->name);
684 res = 1;
686 if (h->text[strlen (h->text) - 1] == '.') {
687 g_printerr ("%s: Unwanted period in ARG record\n",
688 fd->name);
689 res = 1;
691 if (check_argument_refs (aend + 1, fd)) {
692 g_printerr ("%s: Invalid argument reference in argument\n",
693 fd->name);
694 res = 1;
696 argname = g_strndup (h->text, aend - h->text);
697 if (g_hash_table_lookup (allargs, argname)) {
698 g_printerr ("%s: Duplicate argument name %s\n",
699 fd->name, argname);
700 res = 1;
701 g_free (argname);
702 g_printerr ("%s\n", h->text);
703 } else
704 g_hash_table_insert (allargs, argname, argname);
705 break;
707 case GNM_FUNC_HELP_DESCRIPTION: {
708 const char *p;
710 if (check_argument_refs (h->text, fd)) {
711 g_printerr ("%s: Invalid argument reference in description\n",
712 fd->name);
713 res = 1;
716 p = h->text;
717 while (g_ascii_isupper (*p) ||
718 (p != h->text && (*p == '_' ||
719 *p == '.' ||
720 g_ascii_isdigit (*p))))
721 p++;
722 if (*p == ' ' &&
723 p - h->text >= 2 &&
724 strncmp (h->text, "CP1252", 6) != 0) {
725 if (g_ascii_strncasecmp (h->text, fd->name, nlen)) {
726 g_printerr ("%s: Wrong function name in description\n",
727 fd->name);
728 res = 1;
731 break;
734 case GNM_FUNC_HELP_EXAMPLES:
735 if (h->text[0] == '=') {
736 if (check_help_expression (h->text + 1, fd)) {
737 g_printerr ("%s: Invalid EXAMPLES record\n",
738 fd->name);
739 res = 1;
742 break;
743 default:
744 ; /* Nothing */
748 g_hash_table_destroy (allargs);
750 if (fd->fn_type == GNM_FUNC_TYPE_ARGS) {
751 int n = counts[GNM_FUNC_HELP_ARG];
752 if (n != fd->fn.args.max_args) {
753 g_printerr ("%s: Help for %d args, but takes %d-%d\n",
754 fd->name, n,
755 fd->fn.args.min_args, fd->fn.args.max_args);
756 res = 1;
760 #if 0
761 if (counts[GNM_FUNC_HELP_DESCRIPTION] != 1) {
762 g_printerr ("%s: Help has %d descriptions.\n",
763 fd->name, counts[GNM_FUNC_HELP_DESCRIPTION]);
764 res = 1;
766 #endif
768 if (counts[GNM_FUNC_HELP_NAME] != 1) {
769 g_printerr ("%s: Help has %d NAME records.\n",
770 fd->name, counts[GNM_FUNC_HELP_NAME]);
771 res = 1;
774 if (counts[GNM_FUNC_HELP_EXCEL] > 1) {
775 g_printerr ("%s: Help has %d Excel notes.\n",
776 fd->name, counts[GNM_FUNC_HELP_EXCEL]);
777 res = 1;
780 if (counts[GNM_FUNC_HELP_ODF] > 1) {
781 g_printerr ("%s: Help has %d ODF notes.\n",
782 fd->name, counts[GNM_FUNC_HELP_ODF]);
783 res = 1;
786 return res;
790 gnm_func_sanity_check (void)
792 int res = 0;
793 GPtrArray *ordered;
794 unsigned ui;
796 ordered = g_ptr_array_new ();
797 g_hash_table_foreach (functions_by_name,
798 copy_hash_table_to_ptr_array, ordered);
799 if (ordered->len > 0)
800 qsort (&g_ptr_array_index (ordered, 0),
801 ordered->len, sizeof (gpointer),
802 func_def_cmp);
804 for (ui = 0; ui < ordered->len; ui++) {
805 GnmFunc const *fd = g_ptr_array_index (ordered, ui);
806 if (gnm_func_sanity_check1 (fd))
807 res = 1;
810 g_ptr_array_free (ordered, TRUE);
812 return res;
815 /* ------------------------------------------------------------------------- */
817 static void
818 gnm_func_group_free (GnmFuncGroup *fn_group)
820 g_return_if_fail (fn_group != NULL);
821 g_return_if_fail (fn_group->functions == NULL);
823 if (fn_group->ref_count-- > 1)
824 return;
826 go_string_unref (fn_group->internal_name);
827 go_string_unref (fn_group->display_name);
828 g_free (fn_group);
831 static GnmFuncGroup *
832 gnm_func_group_ref (GnmFuncGroup *fn_group)
834 fn_group->ref_count++;
835 return fn_group;
838 GType
839 gnm_func_group_get_type (void)
841 static GType t = 0;
843 if (t == 0) {
844 t = g_boxed_type_register_static ("GnmFuncGroup",
845 (GBoxedCopyFunc)gnm_func_group_ref,
846 (GBoxedFreeFunc)gnm_func_group_free);
848 return t;
851 static gint
852 function_category_compare (gconstpointer a, gconstpointer b)
854 GnmFuncGroup const *cat_a = a;
855 GnmFuncGroup const *cat_b = b;
857 return go_string_cmp (cat_a->display_name, cat_b->display_name);
860 GnmFuncGroup *
861 gnm_func_group_fetch (char const *name, char const *translation)
863 GnmFuncGroup *cat = NULL;
864 GList *l;
866 g_return_val_if_fail (name != NULL, NULL);
868 for (l = categories; l != NULL; l = l->next) {
869 cat = l->data;
870 if (strcmp (cat->internal_name->str, name) == 0) {
871 break;
875 if (l == NULL) {
876 cat = g_new (GnmFuncGroup, 1);
877 cat->internal_name = go_string_new (name);
878 cat->ref_count = 1;
879 if (translation != NULL) {
880 cat->display_name = go_string_new (translation);
881 cat->has_translation = TRUE;
882 } else {
883 cat->display_name = go_string_new (name);
884 cat->has_translation = FALSE;
886 cat->functions = NULL;
887 categories = g_list_insert_sorted (
888 categories, cat, &function_category_compare);
889 } else if (translation != NULL && translation != name &&
890 !cat->has_translation) {
891 go_string_unref (cat->display_name);
892 cat->display_name = go_string_new (translation);
893 cat->has_translation = TRUE;
894 categories = g_list_remove_link (categories, l);
895 g_list_free_1 (l);
896 categories = g_list_insert_sorted (
897 categories, cat, &function_category_compare);
900 return cat;
903 GnmFuncGroup *
904 gnm_func_group_get_nth (int n)
906 return g_list_nth_data (categories, n);
909 static void
910 gnm_func_group_add_func (GnmFuncGroup *fn_group, GnmFunc *fn_def)
912 g_return_if_fail (fn_group != NULL);
913 g_return_if_fail (fn_def != NULL);
915 fn_group->functions = g_slist_prepend (fn_group->functions, fn_def);
918 static void
919 gnm_func_group_remove_func (GnmFuncGroup *fn_group, GnmFunc *fn_def)
921 g_return_if_fail (fn_group != NULL);
922 g_return_if_fail (fn_def != NULL);
924 fn_group->functions = g_slist_remove (fn_group->functions, fn_def);
925 if (fn_group->functions == NULL) {
926 categories = g_list_remove (categories, fn_group);
927 if (unknown_cat == fn_group)
928 unknown_cat = NULL;
929 gnm_func_group_free (fn_group);
933 /******************************************************************************/
935 static void
936 extract_arg_types (GnmFunc *def)
938 int i;
940 function_def_count_args (def,
941 &def->fn.args.min_args,
942 &def->fn.args.max_args);
943 def->fn.args.arg_types = g_malloc (def->fn.args.max_args + 1);
944 for (i = 0; i < def->fn.args.max_args; i++)
945 def->fn.args.arg_types[i] = function_def_get_arg_type (def, i);
946 def->fn.args.arg_types[i] = 0;
949 static GnmValue *
950 error_function_no_full_info (GnmFuncEvalInfo *ei,
951 int argc,
952 GnmExprConstPtr const *argv)
954 return value_new_error (ei->pos, _("Function implementation not available."));
957 static void
958 gnm_func_clear_arg_names (GnmFunc *fd)
960 if (fd->arg_names_p) {
961 g_ptr_array_foreach (fd->arg_names_p, (GFunc) g_free, NULL);
962 g_ptr_array_free (fd->arg_names_p, TRUE);
963 fd->arg_names_p = NULL;
967 static void
968 gnm_func_create_arg_names (GnmFunc *fn_def)
970 int i;
971 GPtrArray *ptr;
973 g_return_if_fail (fn_def != NULL);
975 ptr = g_ptr_array_new ();
976 for (i = 0;
977 fn_def->help && fn_def->help[i].type != GNM_FUNC_HELP_END;
978 i++) {
979 if (fn_def->help[i].type != GNM_FUNC_HELP_ARG)
980 continue;
982 g_ptr_array_add
983 (ptr, split_at_colon
984 (F2(fn_def, fn_def->help[i].text), NULL));
987 gnm_func_clear_arg_names (fn_def);
988 fn_def->arg_names_p = ptr;
992 void
993 gnm_func_load_stub (GnmFunc *func)
995 GnmFuncDescriptor desc;
997 g_return_if_fail (func->fn_type == GNM_FUNC_TYPE_STUB);
999 /* default the content to 0 in case we add new fields
1000 * later and the services do not fill them in
1002 memset (&desc, 0, sizeof (GnmFuncDescriptor));
1004 if (func->fn.load_desc (func, &desc)) {
1005 func->help = desc.help ? desc.help : NULL;
1006 if (desc.fn_args != NULL) {
1007 func->fn_type = GNM_FUNC_TYPE_ARGS;
1008 func->fn.args.func = desc.fn_args;
1009 func->fn.args.arg_spec = desc.arg_spec;
1010 extract_arg_types (func);
1011 } else if (desc.fn_nodes != NULL) {
1012 func->fn_type = GNM_FUNC_TYPE_NODES;
1013 func->fn.nodes = desc.fn_nodes;
1014 } else {
1015 g_warning ("Invalid function descriptor with no function");
1017 func->linker = desc.linker;
1018 func->impl_status = desc.impl_status;
1019 func->test_status = desc.test_status;
1020 func->flags = desc.flags;
1021 gnm_func_create_arg_names (func);
1022 } else {
1023 func->fn_type = GNM_FUNC_TYPE_NODES;
1024 func->fn.nodes = &error_function_no_full_info;
1025 func->linker = NULL;
1029 static void
1030 gnm_func_set_localized_name (GnmFunc *fd, const char *lname)
1032 gboolean in_hashes = !(fd->flags & GNM_FUNC_IS_WORKBOOK_LOCAL);
1034 if (in_hashes && fd->localized_name)
1035 g_hash_table_remove (functions_by_localized_name, fd->localized_name);
1036 g_free (fd->localized_name);
1038 fd->localized_name = g_strdup (lname);
1039 if (in_hashes && lname)
1040 g_hash_table_insert (functions_by_localized_name,
1041 fd->localized_name, fd);
1044 void
1045 gnm_func_free (GnmFunc *func)
1047 GnmFuncGroup *group;
1049 g_return_if_fail (func != NULL);
1050 g_return_if_fail (func->usage_count == 0);
1052 group = func->fn_group;
1053 if (group != NULL)
1054 gnm_func_group_remove_func (group, func);
1056 gnm_func_set_localized_name (func, NULL);
1058 if (!(func->flags & GNM_FUNC_IS_WORKBOOK_LOCAL)) {
1059 g_hash_table_remove (functions_by_name, func->name);
1062 if (func->fn_type == GNM_FUNC_TYPE_ARGS)
1063 g_free (func->fn.args.arg_types);
1065 g_free ((char *)func->name);
1067 if (func->textdomain)
1068 go_string_unref (func->textdomain);
1070 gnm_func_clear_arg_names (func);
1072 g_free (func);
1075 GnmFunc *
1076 gnm_func_ref (GnmFunc *func)
1078 g_return_val_if_fail (func != NULL, NULL);
1080 func->usage_count++;
1081 if (func->usage_count == 1 && func->usage_notify != NULL)
1082 func->usage_notify (func, 1);
1083 return func;
1086 void
1087 gnm_func_unref (GnmFunc *func)
1089 g_return_if_fail (func != NULL);
1090 g_return_if_fail (func->usage_count > 0);
1092 func->usage_count--;
1093 if (func->usage_count == 0 && func->usage_notify != NULL)
1094 func->usage_notify (func, 0);
1097 GType
1098 gnm_func_get_type (void)
1100 static GType t = 0;
1102 if (t == 0) {
1103 t = g_boxed_type_register_static ("GnmFunc",
1104 (GBoxedCopyFunc)gnm_func_ref,
1105 (GBoxedFreeFunc)gnm_func_unref);
1107 return t;
1110 GnmFunc *
1111 gnm_func_lookup (char const *name, Workbook *scope)
1113 GnmFunc *fd = g_hash_table_lookup (functions_by_name, name);
1114 if (fd != NULL)
1115 return fd;
1116 if (scope == NULL || scope->sheet_local_functions == NULL)
1117 return NULL;
1118 return g_hash_table_lookup (scope->sheet_local_functions, (gpointer)name);
1121 GnmFunc *
1122 gnm_func_lookup_localized (char const *name, Workbook *scope)
1124 GnmFunc *fd;
1125 GHashTableIter hiter;
1126 gpointer value;
1128 /* Must localize all function names. */
1129 g_hash_table_iter_init (&hiter, functions_by_name);
1130 while (g_hash_table_iter_next (&hiter, NULL, &value)) {
1131 GnmFunc *fd = value;
1132 (void)gnm_func_get_name (fd, TRUE);
1135 fd = g_hash_table_lookup (functions_by_localized_name, name);
1136 if (fd != NULL)
1137 return fd;
1138 if (scope == NULL || scope->sheet_local_functions == NULL)
1139 return NULL;
1140 return g_hash_table_lookup (scope->sheet_local_functions, (gpointer)name);
1144 * gnm_func_lookup_prefix:
1145 * @prefix: prefix to search for
1146 * @scope:
1147 * @trans: whether to search translated function names
1149 * Returns: (element-type GnmFunc*) (transfer full):
1151 GSList *
1152 gnm_func_lookup_prefix (char const *prefix, Workbook *scope, gboolean trans)
1154 GSList *res = NULL;
1155 GHashTableIter hiter;
1156 gpointer value;
1159 * Always iterate over functions_by_name as the localized name
1160 * might not be set yet.
1162 g_hash_table_iter_init (&hiter, functions_by_name);
1163 while (g_hash_table_iter_next (&hiter, NULL, &value)) {
1164 GnmFunc *fd = value;
1165 if (!(fd->flags & GNM_FUNC_IS_PLACEHOLDER)) {
1166 const char *name = gnm_func_get_name (fd, trans);
1167 if (g_str_has_prefix (name, prefix)) {
1168 gnm_func_ref (fd);
1169 res = g_slist_prepend (res, fd);
1174 return res;
1177 GnmFunc *
1178 gnm_func_add (GnmFuncGroup *fn_group,
1179 GnmFuncDescriptor const *desc,
1180 const char *textdomain)
1182 static char const valid_tokens[] = "fsbraAES?|";
1183 GnmFunc *func;
1184 char const *ptr;
1186 g_return_val_if_fail (fn_group != NULL, NULL);
1187 g_return_val_if_fail (desc != NULL, NULL);
1189 func = g_new (GnmFunc, 1);
1191 if (!textdomain)
1192 textdomain = GETTEXT_PACKAGE;
1194 func->name = g_strdup (desc->name);
1195 func->help = desc->help ? desc->help : NULL;
1196 func->textdomain = go_string_new (textdomain);
1197 func->linker = desc->linker;
1198 func->usage_notify = desc->usage_notify;
1199 func->flags = desc->flags;
1200 func->impl_status = desc->impl_status;
1201 func->test_status = desc->test_status;
1202 func->localized_name = NULL;
1203 func->arg_names_p = NULL;
1205 func->user_data = NULL;
1206 func->usage_count = 0;
1208 if (desc->fn_args != NULL) {
1209 /* Check those arguments */
1210 for (ptr = desc->arg_spec ; *ptr ; ptr++) {
1211 g_return_val_if_fail (strchr (valid_tokens, *ptr), NULL);
1214 func->fn_type = GNM_FUNC_TYPE_ARGS;
1215 func->fn.args.func = desc->fn_args;
1216 func->fn.args.arg_spec = desc->arg_spec;
1217 extract_arg_types (func);
1218 } else if (desc->fn_nodes != NULL) {
1220 if (desc->arg_spec && *desc->arg_spec) {
1221 g_warning ("Arg spec for node function -- why?");
1224 func->fn_type = GNM_FUNC_TYPE_NODES;
1225 func->fn.nodes = desc->fn_nodes;
1226 } else {
1227 g_warning ("Invalid function has neither args nor nodes handler");
1228 g_free (func);
1229 return NULL;
1232 func->fn_group = fn_group;
1233 if (fn_group != NULL)
1234 gnm_func_group_add_func (fn_group, func);
1235 if (!(func->flags & GNM_FUNC_IS_WORKBOOK_LOCAL))
1236 g_hash_table_insert (functions_by_name,
1237 (gpointer)(func->name), func);
1239 gnm_func_create_arg_names (func);
1241 return func;
1244 /* Handle unknown functions on import without losing their names */
1245 static GnmValue *
1246 unknownFunctionHandler (GnmFuncEvalInfo *ei,
1247 G_GNUC_UNUSED int argc,
1248 G_GNUC_UNUSED GnmExprConstPtr const *argv)
1250 return value_new_error_NAME (ei->pos);
1254 * gnm_func_upgrade_placeholder:
1255 * @fd:
1256 * @fn_group:
1257 * @textdomain:
1258 * @load_desc: (scope async):
1259 * @opt_usage_notify: (scope async):
1261 void
1262 gnm_func_upgrade_placeholder (GnmFunc *fd,
1263 GnmFuncGroup *fn_group,
1264 const char *textdomain,
1265 GnmFuncLoadDesc load_desc,
1266 GnmFuncUsageNotify opt_usage_notify)
1268 g_return_if_fail (fd != NULL);
1269 g_return_if_fail (fd->flags & GNM_FUNC_IS_PLACEHOLDER);
1270 g_return_if_fail (fn_group != NULL);
1272 if (!textdomain)
1273 textdomain = GETTEXT_PACKAGE;
1275 /* Remove from unknown_cat */
1276 gnm_func_group_remove_func (fd->fn_group, fd);
1278 fd->fn_type = GNM_FUNC_TYPE_STUB;
1279 fd->fn.load_desc = load_desc;
1280 fd->usage_notify = opt_usage_notify;
1282 go_string_unref (fd->textdomain);
1283 fd->textdomain = go_string_new (textdomain);
1285 /* Clear localized_name so we can deduce the proper name. */
1286 gnm_func_set_localized_name (fd, NULL);
1288 fd->flags &= ~GNM_FUNC_IS_PLACEHOLDER;
1290 fd->fn_group = fn_group;
1291 gnm_func_group_add_func (fn_group, fd);
1294 static char *
1295 invent_name (const char *pref, GHashTable *h, const char *template)
1297 static int count = 0;
1298 char *name = g_utf8_strdown (pref, -1);
1300 while (g_hash_table_lookup (h, name)) {
1301 count++;
1302 g_free (name);
1303 name = g_strdup_printf (template, count);
1306 return name;
1309 static GnmFunc *
1310 gnm_func_add_placeholder_full (Workbook *scope,
1311 char const *gname, char const *lname,
1312 char const *type)
1314 GnmFuncDescriptor desc;
1315 GnmFunc *func;
1316 char const *unknown_cat_name = N_("Unknown Function");
1317 gboolean copy_gname = TRUE;
1318 gboolean copy_lname = TRUE;
1320 g_return_val_if_fail (gname || lname, NULL);
1321 g_return_val_if_fail (gname == NULL || gnm_func_lookup (gname, scope) == NULL, NULL);
1322 g_return_val_if_fail (lname == NULL || gnm_func_lookup_localized (lname, scope) == NULL, NULL);
1324 if (!unknown_cat)
1325 unknown_cat = gnm_func_group_fetch
1326 (unknown_cat_name, _(unknown_cat_name));
1328 if (!gname) {
1330 * This is actually a bit of a problem if we don't end up
1331 * with a copy of lname (because there already is a function
1332 * with that name). We're likely to save a template name,
1333 * but I don't see what else to do.
1335 gname = invent_name (lname, functions_by_name, "unknown%d");
1336 copy_gname = FALSE;
1338 if (!lname) {
1339 /* xgettext: This represents a made-up translated function name. */
1340 lname = invent_name (gname, functions_by_localized_name, _("unknown%d"));
1341 copy_lname = FALSE;
1344 if (gnm_debug_flag ("func"))
1345 g_printerr ("Adding placeholder for %s (aka %s)\n", gname, lname);
1347 memset (&desc, 0, sizeof (GnmFuncDescriptor));
1348 desc.name = gname;
1349 desc.arg_spec = NULL;
1350 desc.help = NULL;
1351 desc.fn_args = NULL;
1352 desc.fn_nodes = &unknownFunctionHandler;
1353 desc.linker = NULL;
1354 desc.usage_notify = NULL;
1355 desc.flags = GNM_FUNC_IS_PLACEHOLDER;
1356 desc.impl_status = GNM_FUNC_IMPL_STATUS_EXISTS;
1357 desc.test_status = GNM_FUNC_TEST_STATUS_UNKNOWN;
1359 if (scope != NULL)
1360 desc.flags |= GNM_FUNC_IS_WORKBOOK_LOCAL;
1361 else {
1362 #if 0
1363 /* WISHLIST : it would be nice to have a log if these. */
1364 g_warning ("Unknown %s function : %s", type, desc.name);
1365 #endif
1368 func = gnm_func_add (unknown_cat, &desc, NULL);
1370 if (lname) {
1371 gnm_func_set_localized_name (func, lname);
1372 if (!copy_lname)
1373 g_free ((char *)lname);
1376 if (!copy_gname)
1377 g_free ((char *)gname);
1379 if (scope != NULL) {
1380 if (scope->sheet_local_functions == NULL)
1381 scope->sheet_local_functions = g_hash_table_new_full (
1382 g_str_hash, g_str_equal,
1383 NULL, (GDestroyNotify) gnm_func_free);
1384 g_hash_table_insert (scope->sheet_local_functions,
1385 (gpointer)func->name, func);
1388 return func;
1392 * When importing it is useful to keep track of unknown function names.
1393 * We may be missing a plugin or something similar.
1395 * TODO : Eventully we should be able to keep track of these
1396 * and replace them with something else. Possibly even reordering the
1397 * arguments.
1399 GnmFunc *
1400 gnm_func_add_placeholder (Workbook *scope,
1401 char const *name, char const *type)
1403 return gnm_func_add_placeholder_full (scope, name, NULL, type);
1406 GnmFunc *
1407 gnm_func_add_placeholder_localized (char const *gname, char const *lname)
1409 return gnm_func_add_placeholder_full (NULL, gname, lname, "?");
1412 /* Utility routine to be used for import and analysis tools */
1413 GnmFunc *
1414 gnm_func_lookup_or_add_placeholder (char const *name)
1416 GnmFunc * f = gnm_func_lookup (name, NULL);
1417 if (f == NULL)
1418 f = gnm_func_add_placeholder (NULL, name, "");
1419 return f;
1423 * gnm_func_get_user_data:
1424 * @func:
1426 * Returns: (transfer none):
1428 gpointer
1429 gnm_func_get_user_data (GnmFunc const *func)
1431 g_return_val_if_fail (func != NULL, NULL);
1433 return func->user_data;
1436 void
1437 gnm_func_set_user_data (GnmFunc *func, gpointer user_data)
1439 g_return_if_fail (func != NULL);
1441 func->user_data = user_data;
1444 char const *
1445 gnm_func_get_name (GnmFunc const *func, gboolean localized_function_names)
1447 int i;
1448 GnmFunc *fd = (GnmFunc *)func;
1450 g_return_val_if_fail (func != NULL, NULL);
1452 if (!localized_function_names)
1453 return func->name;
1455 if (func->localized_name)
1456 return func->localized_name;
1459 * Deduce the translated names from the help texts. This
1460 * code doesn't currently check for clashes in translated
1461 * names.
1464 gnm_func_load_if_stub (fd);
1466 for (i = 0;
1467 (func->localized_name == NULL &&
1468 func->help &&
1469 func->help[i].type != GNM_FUNC_HELP_END);
1470 i++) {
1471 const char *s, *sl;
1472 char *U;
1473 if (func->help[i].type != GNM_FUNC_HELP_NAME)
1474 continue;
1476 s = func->help[i].text;
1477 sl = F2 (func, s);
1478 if (s == sl) /* String not actually translated. */
1479 continue;
1481 U = split_at_colon (F2 (func, s), NULL);
1482 if (U) {
1483 char *lname = g_utf8_strdown (U, -1);
1484 gnm_func_set_localized_name (fd, lname);
1485 g_free (lname);
1487 g_free (U);
1490 if (!func->localized_name)
1491 gnm_func_set_localized_name (fd, fd->name);
1493 return func->localized_name;
1497 * gnm_func_get_description:
1498 * @fn_def: the fn defintion
1500 * Return value: the description of the function
1503 char const*
1504 gnm_func_get_description (GnmFunc const *fn_def)
1506 gint i;
1507 g_return_val_if_fail (fn_def != NULL, NULL);
1509 gnm_func_load_if_stub ((GnmFunc *)fn_def);
1511 for (i = 0;
1512 fn_def->help && fn_def->help[i].type != GNM_FUNC_HELP_END;
1513 i++) {
1514 const char *desc;
1516 if (fn_def->help[i].type != GNM_FUNC_HELP_NAME)
1517 continue;
1519 desc = strchr (F2 (fn_def, fn_def->help[i].text), ':');
1520 return desc ? (desc + 1) : "";
1522 return "";
1526 * function_def_count_args:
1527 * @fn_def: pointer to function definition
1528 * @min: pointer to min. args
1529 * @max: pointer to max. args
1531 * This calculates the max and min args that
1532 * can be passed; NB max can be G_MAXINT for
1533 * a vararg function.
1534 * NB. this data is not authoratitive for a
1535 * 'nodes' function.
1538 void
1539 function_def_count_args (GnmFunc const *fn_def,
1540 int *min, int *max)
1542 char const *ptr;
1543 int i;
1544 int vararg;
1546 g_return_if_fail (min != NULL);
1547 g_return_if_fail (max != NULL);
1548 g_return_if_fail (fn_def != NULL);
1550 gnm_func_load_if_stub ((GnmFunc *)fn_def);
1553 * FIXME: clearly for 'nodes' functions many of
1554 * the type fields will need to be filled.
1556 if (fn_def->fn_type == GNM_FUNC_TYPE_NODES) {
1557 *min = 0;
1558 if (g_ascii_strcasecmp ("INDEX",fn_def->name) == 0)
1559 *max = 4;
1560 else
1561 *max = G_MAXINT;
1562 return;
1565 ptr = fn_def->fn.args.arg_spec;
1566 for (i = vararg = 0; ptr && *ptr; ptr++) {
1567 if (*ptr == '|') {
1568 vararg = 1;
1569 *min = i;
1570 } else
1571 i++;
1573 *max = i;
1574 if (!vararg)
1575 *min = i;
1579 * function_def_get_arg_type:
1580 * @fn_def: the fn defintion
1581 * @arg_idx: zero based argument offset
1583 * Return value: the type of the argument
1585 char
1586 function_def_get_arg_type (GnmFunc const *fn_def, int arg_idx)
1588 char const *ptr;
1590 g_return_val_if_fail (arg_idx >= 0, '?');
1591 g_return_val_if_fail (fn_def != NULL, '?');
1593 gnm_func_load_if_stub ((GnmFunc *)fn_def);
1595 switch (fn_def->fn_type) {
1596 case GNM_FUNC_TYPE_ARGS:
1597 for (ptr = fn_def->fn.args.arg_spec; ptr && *ptr; ptr++) {
1598 if (*ptr == '|')
1599 continue;
1600 if (arg_idx-- == 0)
1601 return *ptr;
1603 return '?';
1605 case GNM_FUNC_TYPE_NODES:
1606 return '?'; /* Close enough for now. */
1608 case GNM_FUNC_TYPE_STUB:
1609 #ifndef DEBUG_SWITCH_ENUM
1610 default:
1611 #endif
1612 g_assert_not_reached ();
1613 return '?';
1618 * function_def_get_arg_type_string:
1619 * @fn_def: the fn defintion
1620 * @arg_idx: zero based argument offset
1622 * Return value: the type of the argument as a string
1624 char const *
1625 function_def_get_arg_type_string (GnmFunc const *fn_def,
1626 int arg_idx)
1628 switch (function_def_get_arg_type (fn_def, arg_idx)) {
1629 case 'f':
1630 return _("Number");
1631 case 's':
1632 return _("String");
1633 case 'b':
1634 return _("Boolean");
1635 case 'r':
1636 return _("Cell Range");
1637 case 'A':
1638 return _("Area");
1639 case 'E':
1640 return _("Scalar, Blank, or Error");
1641 case 'S':
1642 return _("Scalar");
1643 case '?':
1644 /* Missing values will be NULL. */
1645 return _("Any");
1647 default:
1648 g_warning ("Unknown arg type");
1649 return "Broken";
1654 * function_def_get_arg_name:
1655 * @fn_def: the fn defintion
1656 * @arg_idx: zero based argument offset
1658 * Return value: the name of the argument (must be freed)
1660 char *
1661 function_def_get_arg_name (GnmFunc const *fn_def, guint arg_idx)
1663 g_return_val_if_fail (fn_def != NULL, NULL);
1665 gnm_func_load_if_stub ((GnmFunc *)fn_def);
1667 if ((fn_def->arg_names_p != NULL)
1668 && (arg_idx < fn_def->arg_names_p->len))
1669 return g_strdup (g_ptr_array_index (fn_def->arg_names_p,
1670 arg_idx));
1671 return NULL;
1675 * gnm_func_get_arg_description:
1676 * @fn_def: the fn defintion
1677 * @arg_idx: zero based argument offset
1679 * Return value: the namedescription of the argument
1681 char const*
1682 gnm_func_get_arg_description (GnmFunc const *fn_def, guint arg_idx)
1684 gint i;
1685 g_return_val_if_fail (fn_def != NULL, NULL);
1687 gnm_func_load_if_stub ((GnmFunc *)fn_def);
1689 for (i = 0;
1690 fn_def->help && fn_def->help[i].type != GNM_FUNC_HELP_END;
1691 i++) {
1692 gchar const *desc;
1694 if (fn_def->help[i].type != GNM_FUNC_HELP_ARG)
1695 continue;
1696 if (arg_idx--)
1697 continue;
1699 desc = strchr (F2 (fn_def, fn_def->help[i].text), ':');
1700 if (!desc)
1701 return "";
1703 desc++;
1704 while (g_unichar_isspace (g_utf8_get_char (desc)))
1705 desc = g_utf8_next_char (desc);
1706 return desc;
1709 return "";
1713 * gnm_func_convert_markup_to_pango:
1714 * @desc: the fn or arg description string
1715 * @target: target widget for the markup.
1717 * Return value: the escaped string with @{} markup converted to
1718 * pango markup
1720 char *
1721 gnm_func_convert_markup_to_pango (char const *desc, GtkWidget *target)
1723 GString *str;
1724 gchar *markup, *at;
1725 GdkColor *link_color = NULL;
1726 char *link_color_text, *span_text;
1727 size_t span_text_len;
1729 gtk_widget_style_get (target, "link-color", &link_color, NULL);
1730 link_color_text = gdk_color_to_string (link_color);
1731 gdk_color_free (link_color);
1732 span_text = g_strdup_printf ("<span foreground=\"%s\">",
1733 link_color_text);
1734 span_text_len = strlen (span_text);
1735 g_free (link_color_text);
1737 markup = g_markup_escape_text (desc, -1);
1738 str = g_string_new (markup);
1739 g_free (markup);
1741 while ((at = strstr (str->str, "@{"))) {
1742 gint len = at - str->str;
1743 go_string_replace (str, len, 2, span_text, -1);
1744 if ((at = strstr
1745 (str->str + len + span_text_len, "}"))) {
1746 len = at - str->str;
1747 go_string_replace (str, len, 1, "</span>", -1);
1748 } else
1749 g_string_append (str, "</span>");
1751 g_free (span_text);
1753 return g_string_free (str, FALSE);
1757 /* ------------------------------------------------------------------------- */
1759 static inline void
1760 free_values (GnmValue **values, int top)
1762 int i;
1764 for (i = 0; i < top; i++)
1765 if (values [i])
1766 value_release (values [i]);
1769 /* ------------------------------------------------------------------------- */
1772 * function_call_with_exprs:
1773 * @ei: EvalInfo containing valid fn_def!
1775 * Do the guts of calling a function.
1777 * Returns the result.
1779 GnmValue *
1780 function_call_with_exprs (GnmFuncEvalInfo *ei)
1782 GnmFunc const *fn_def;
1783 int i, iter_count, iter_width = 0, iter_height = 0;
1784 char arg_type;
1785 GnmValue **args, *tmp = NULL;
1786 int *iter_item = NULL;
1787 int argc;
1788 GnmExprConstPtr *argv;
1789 GnmExprEvalFlags flags, pass_flags;
1791 g_return_val_if_fail (ei != NULL, NULL);
1792 g_return_val_if_fail (ei->func_call != NULL, NULL);
1794 flags = ei->flags;
1796 argc = ei->func_call->argc;
1797 argv = ei->func_call->argv;
1798 fn_def = ei->func_call->func;
1800 gnm_func_load_if_stub ((GnmFunc *)fn_def);
1802 /* Functions that deal with ExprNodes */
1803 if (fn_def->fn_type == GNM_FUNC_TYPE_NODES)
1804 return fn_def->fn.nodes (ei, argc, argv);
1806 /* Functions that take pre-computed Values */
1807 if (argc > fn_def->fn.args.max_args ||
1808 argc < fn_def->fn.args.min_args)
1809 return value_new_error_NA (ei->pos);
1811 args = g_alloca (sizeof (GnmValue *) * fn_def->fn.args.max_args);
1812 iter_count = (eval_pos_is_array_context (ei->pos) &&
1813 (flags & GNM_EXPR_EVAL_PERMIT_NON_SCALAR))
1814 ? 0 : -1;
1816 /* Optimization for IF when implicit iteration is not used. */
1817 if (ei->func_call->func->fn.args.func == gnumeric_if &&
1818 iter_count == -1)
1819 return gnumeric_if2 (ei, argc, argv, flags);
1821 pass_flags = (flags &
1822 (GNM_EXPR_EVAL_ARRAY_CONTEXT));
1824 for (i = 0; i < argc; i++) {
1825 char arg_type = fn_def->fn.args.arg_types[i];
1826 /* expr is always non-null, missing args are encoded as
1827 * const = empty */
1828 GnmExpr const *expr = argv[i];
1830 if (arg_type == 'A' || arg_type == 'r') {
1831 tmp = args[i] = gnm_expr_eval
1832 (expr, ei->pos,
1833 pass_flags |
1834 GNM_EXPR_EVAL_PERMIT_NON_SCALAR |
1835 GNM_EXPR_EVAL_WANT_REF);
1836 if (VALUE_IS_ERROR (tmp)) {
1837 free_values (args, i);
1838 return tmp;
1841 if (tmp->type == VALUE_CELLRANGE) {
1842 gnm_cellref_make_abs (&tmp->v_range.cell.a,
1843 &tmp->v_range.cell.a,
1844 ei->pos);
1845 gnm_cellref_make_abs (&tmp->v_range.cell.b,
1846 &tmp->v_range.cell.b,
1847 ei->pos);
1848 /* Array args accept scalars */
1849 } else if (arg_type != 'A' && tmp->type != VALUE_ARRAY) {
1850 free_values (args, i + 1);
1851 return value_new_error_VALUE (ei->pos);
1853 continue;
1856 /* force scalars whenever we are certain */
1857 tmp = args[i] = gnm_expr_eval
1858 (expr, ei->pos,
1859 pass_flags |
1860 GNM_EXPR_EVAL_PERMIT_EMPTY |
1861 (iter_count >= 0 || arg_type == '?'
1862 ? GNM_EXPR_EVAL_PERMIT_NON_SCALAR
1863 : 0));
1865 if (arg_type == '?') /* '?' arguments are unrestriced */
1866 continue;
1868 /* optional arguments can be blank */
1869 if (i >= fn_def->fn.args.min_args && VALUE_IS_EMPTY (tmp)) {
1870 if (arg_type == 'E' && !gnm_expr_is_empty (expr)) {
1871 /* An actual argument produced empty. Make
1872 sure function sees that. */
1873 args[i] = value_new_empty ();
1876 continue;
1879 if (tmp == NULL)
1880 tmp = args[i] = value_new_empty ();
1882 /* Handle implicit intersection or iteration depending on flags */
1883 if (tmp->type == VALUE_CELLRANGE || tmp->type == VALUE_ARRAY) {
1884 if (iter_count > 0) {
1885 if (iter_width != value_area_get_width (tmp, ei->pos) ||
1886 iter_height != value_area_get_height (tmp, ei->pos)) {
1887 free_values (args, i + 1);
1888 return value_new_error_VALUE (ei->pos);
1890 } else {
1891 if (iter_count < 0) {
1892 g_warning ("Damn I thought this was impossible");
1893 iter_count = 0;
1895 iter_item = g_alloca (sizeof (int) * argc);
1896 iter_width = value_area_get_width (tmp, ei->pos);
1897 iter_height = value_area_get_height (tmp, ei->pos);
1899 iter_item [iter_count++] = i;
1901 /* no need to check type, we would fail comparing a range against a "b, f, or s" */
1902 continue;
1905 /* All of these argument types must be scalars */
1906 switch (arg_type) {
1907 case 'b':
1908 if (VALUE_IS_STRING (tmp)) {
1909 gboolean err;
1910 gboolean b = value_get_as_bool (tmp, &err);
1911 if (err) {
1912 free_values (args, i + 1);
1913 return value_new_error_VALUE (ei->pos);
1915 value_release (args[i]);
1916 tmp = args[i] = value_new_bool (b);
1917 break;
1919 /* Fall through. */
1920 case 'f':
1921 if (VALUE_IS_STRING (tmp)) {
1922 tmp = format_match_number (value_peek_string (tmp), NULL,
1923 workbook_date_conv (ei->pos->sheet->workbook));
1924 if (tmp == NULL) {
1925 free_values (args, i + 1);
1926 return value_new_error_VALUE (ei->pos);
1928 value_release (args [i]);
1929 args[i] = tmp;
1930 } else if (VALUE_IS_ERROR (tmp)) {
1931 free_values (args, i);
1932 return tmp;
1933 } else if (VALUE_IS_EMPTY (tmp)) {
1934 value_release (args [i]);
1935 tmp = args[i] = value_new_int (0);
1938 if (!VALUE_IS_NUMBER (tmp))
1939 return value_new_error_VALUE (ei->pos);
1940 break;
1942 case 's':
1943 case 'S':
1944 if (VALUE_IS_ERROR (tmp)) {
1945 free_values (args, i);
1946 return tmp;
1948 break;
1950 case 'E': /* nothing necessary */
1951 break;
1953 /* case '?': handled above */
1954 default :
1955 g_warning ("Unknown argument type '%c'", arg_type);
1956 break;
1960 while (i < fn_def->fn.args.max_args)
1961 args [i++] = NULL;
1963 if (iter_item != NULL) {
1964 int x, y;
1965 GnmValue *res = value_new_array_empty (iter_width, iter_height);
1966 GnmValue const *elem, *err;
1967 GnmValue **iter_vals = g_alloca (sizeof (GnmValue *) * iter_count);
1968 GnmValue **iter_args = g_alloca (sizeof (GnmValue *) * iter_count);
1970 /* collect the args we will iterate on */
1971 for (i = 0 ; i < iter_count; i++)
1972 iter_vals[i] = args[iter_item[i]];
1974 for (x = iter_width; x-- > 0 ; )
1975 for (y = iter_height; y-- > 0 ; ) {
1976 /* marshal the args */
1977 err = NULL;
1978 for (i = 0 ; i < iter_count; i++) {
1979 elem = value_area_get_x_y (iter_vals[i], x, y, ei->pos);
1980 arg_type = fn_def->fn.args.arg_types[iter_item[i]];
1981 if (arg_type == 'b' || arg_type == 'f') {
1982 if (VALUE_IS_EMPTY (elem))
1983 elem = value_zero;
1984 else if (VALUE_IS_STRING (elem)) {
1985 tmp = format_match_number (value_peek_string (elem), NULL,
1986 workbook_date_conv (ei->pos->sheet->workbook));
1987 if (tmp != NULL) {
1988 args [iter_item[i]] = iter_args [i] = tmp;
1989 continue;
1990 } else
1991 break;
1992 } else if (VALUE_IS_ERROR (elem)) {
1993 err = elem;
1994 break;
1995 } else if (!VALUE_IS_NUMBER (elem))
1996 break;
1997 } else if (arg_type == 's') {
1998 if (VALUE_IS_EMPTY (elem)) {
1999 args [iter_item[i]] = iter_args [i] = value_new_string ("");
2000 continue;
2001 } else if (VALUE_IS_ERROR (elem)) {
2002 err = elem;
2003 break;
2004 } else if (!VALUE_IS_STRING (elem))
2005 break;
2006 } else if (elem == NULL) {
2007 args [iter_item[i]] = iter_args [i] = value_new_empty ();
2008 continue;
2010 args [iter_item[i]] = iter_args [i] = value_dup (elem);
2013 res->v_array.vals[x][y] = (i == iter_count)
2014 ? fn_def->fn.args.func (ei, (GnmValue const * const *)args)
2015 : ((err != NULL) ? value_dup (err)
2016 : value_new_error_VALUE (ei->pos));
2017 free_values (iter_args, i);
2020 /* free the primaries, not the already freed iteration */
2021 for (i = 0 ; i < iter_count; i++)
2022 args[iter_item[i]] = iter_vals[i];
2023 tmp = res;
2024 i = fn_def->fn.args.max_args;
2025 } else
2026 tmp = fn_def->fn.args.func (ei, (GnmValue const * const *)args);
2028 free_values (args, i);
2029 return tmp;
2033 * Use this to invoke a register function: the only drawback is that
2034 * you have to compute/expand all of the values to use this
2036 GnmValue *
2037 function_call_with_values (GnmEvalPos const *ep, char const *fn_name,
2038 int argc, GnmValue const * const *values)
2040 GnmFunc *fn_def;
2042 g_return_val_if_fail (ep != NULL, NULL);
2043 g_return_val_if_fail (fn_name != NULL, NULL);
2044 g_return_val_if_fail (ep->sheet != NULL, NULL);
2046 /* FIXME : support workbook local functions */
2047 fn_def = gnm_func_lookup (fn_name, NULL);
2048 if (fn_def == NULL)
2049 return value_new_error_NAME (ep);
2050 return function_def_call_with_values (ep, fn_def, argc, values);
2053 GnmValue *
2054 function_def_call_with_values (GnmEvalPos const *ep, GnmFunc const *fn_def,
2055 int argc, GnmValue const * const *values)
2057 GnmValue *retval;
2058 GnmExprFunction ef;
2059 GnmFuncEvalInfo fs;
2061 fs.pos = ep;
2062 fs.func_call = &ef;
2063 ef.func = (GnmFunc *)fn_def;
2065 gnm_func_load_if_stub ((GnmFunc *)fn_def);
2067 if (fn_def->fn_type == GNM_FUNC_TYPE_NODES) {
2069 * If function deals with ExprNodes, create some
2070 * temporary ExprNodes with constants.
2072 GnmExprConstant *expr = g_new (GnmExprConstant, argc);
2073 GnmExprConstPtr *argv = g_new (GnmExprConstPtr, argc);
2074 int i;
2076 for (i = 0; i < argc; i++) {
2077 gnm_expr_constant_init (expr + i, values[i]);
2078 argv[i] = (GnmExprConstPtr)(expr + i);
2080 retval = fn_def->fn.nodes (&fs, argc, argv);
2081 g_free (argv);
2082 g_free (expr);
2083 } else
2084 retval = fn_def->fn.args.func (&fs, values);
2086 return retval;
2089 /* ------------------------------------------------------------------------- */
2091 typedef struct {
2092 FunctionIterateCB callback;
2093 void *closure;
2094 gboolean strict;
2095 gboolean ignore_subtotal;
2096 } IterateCallbackClosure;
2099 * cb_iterate_cellrange:
2101 * Helper routine used by the function_iterate_do_value routine.
2102 * Invoked by the sheet cell range iterator.
2104 static GnmValue *
2105 cb_iterate_cellrange (GnmCellIter const *iter, gpointer user)
2108 IterateCallbackClosure *data = user;
2109 GnmCell *cell;
2110 GnmValue *res;
2111 GnmEvalPos ep;
2113 if (NULL == (cell = iter->cell)) {
2114 ep.sheet = iter->pp.sheet;
2115 ep.dep = NULL;
2116 ep.eval.col = iter->pp.eval.col;
2117 ep.eval.row = iter->pp.eval.row;
2118 return (*data->callback)(&ep, NULL, data->closure);
2121 if (data->ignore_subtotal && gnm_cell_has_expr (cell) &&
2122 gnm_expr_top_contains_subtotal (cell->base.texpr))
2123 return NULL;
2125 gnm_cell_eval (cell);
2126 eval_pos_init_cell (&ep, cell);
2128 /* If we encounter an error for the strict case, short-circuit here. */
2129 if (data->strict && (NULL != (res = gnm_cell_is_error (cell))))
2130 return value_new_error_str (&ep, res->v_err.mesg);
2132 /* All other cases -- including error -- just call the handler. */
2133 return (*data->callback)(&ep, cell->value, data->closure);
2137 * function_iterate_do_value:
2139 * Helper routine for function_iterate_argument_values.
2141 static GnmValue *
2142 function_iterate_do_value (GnmEvalPos const *ep,
2143 FunctionIterateCB callback,
2144 gpointer closure,
2145 GnmValue const *value,
2146 gboolean strict,
2147 CellIterFlags iter_flags)
2149 GnmValue *res = NULL;
2151 switch (value->type){
2152 case VALUE_ERROR:
2153 if (strict) {
2154 res = value_dup (value);
2155 break;
2157 /* Fall through. */
2159 case VALUE_EMPTY:
2160 case VALUE_BOOLEAN:
2161 case VALUE_FLOAT:
2162 case VALUE_STRING:
2163 res = (*callback)(ep, value, closure);
2164 break;
2166 case VALUE_ARRAY: {
2167 int x, y;
2169 /* Note the order here. */
2170 for (y = 0; y < value->v_array.y; y++) {
2171 for (x = 0; x < value->v_array.x; x++) {
2172 res = function_iterate_do_value (
2173 ep, callback, closure,
2174 value->v_array.vals [x][y],
2175 strict, CELL_ITER_IGNORE_BLANK);
2176 if (res != NULL)
2177 return res;
2180 break;
2182 case VALUE_CELLRANGE: {
2183 IterateCallbackClosure data;
2185 data.callback = callback;
2186 data.closure = closure;
2187 data.strict = strict;
2188 data.ignore_subtotal = (iter_flags & CELL_ITER_IGNORE_SUBTOTAL) != 0;
2190 res = workbook_foreach_cell_in_range (ep, value, iter_flags,
2191 cb_iterate_cellrange,
2192 &data);
2195 return res;
2199 * function_iterate_argument_values:
2200 * @ep: The position in a workbook at which to evaluate
2201 * @callback: (scope call): The routine to be invoked for every value computed
2202 * @callback_closure: Closure for the callback.
2203 * @argc:
2204 * @argv:
2205 * @strict: If TRUE, the function is considered "strict". This means
2206 * that if an error value occurs as an argument, the iteration
2207 * will stop and that error will be returned. If FALSE, an
2208 * error will be passed on to the callback (as a GnmValue *
2209 * of type VALUE_ERROR).
2210 * @iter_flags:
2212 * Return value:
2213 * NULL : if no errors were reported.
2214 * GnmValue * : if an error was found during strict evaluation
2215 * VALUE_TERMINATE : if the callback requested termination of the iteration.
2217 * This routine provides a simple way for internal functions with variable
2218 * number of arguments to be written: this would iterate over a list of
2219 * expressions (expr_node_list) and will invoke the callback for every
2220 * GnmValue found on the list (this means that ranges get properly expaned).
2222 GnmValue *
2223 function_iterate_argument_values (GnmEvalPos const *ep,
2224 FunctionIterateCB callback,
2225 void *callback_closure,
2226 int argc,
2227 GnmExprConstPtr const *argv,
2228 gboolean strict,
2229 CellIterFlags iter_flags)
2231 GnmValue *result = NULL;
2232 int a;
2234 for (a = 0; result == NULL && a < argc; a++) {
2235 GnmExpr const *expr = argv[a];
2236 GnmValue *val;
2238 if (iter_flags & CELL_ITER_IGNORE_SUBTOTAL &&
2239 gnm_expr_contains_subtotal (expr))
2240 continue;
2242 /* need to drill down into names to handle things like
2243 * sum(name) with name := (A:A,B:B) */
2244 while (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_NAME) {
2245 expr = expr->name.name->texpr->expr;
2246 if (expr == NULL) {
2247 if (strict)
2248 return value_new_error_REF (ep);
2249 continue;
2253 /* Handle sets as a special case */
2254 if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_SET) {
2255 result = function_iterate_argument_values
2256 (ep, callback, callback_closure,
2257 expr->set.argc, expr->set.argv,
2258 strict, iter_flags);
2259 continue;
2262 /* We need a cleaner model of what to do here.
2263 * In non-array mode
2264 * SUM(Range)
2265 * will obviously return Range
2267 * SUM(INDIRECT(Range))
2268 * SUM(INDIRECT(Range):....)
2269 * will do implicit intersection on Range (in non-array mode),
2270 * but allow non-scalar results from indirect (no intersection)
2272 * SUM(Range=3)
2273 * will do implicit intersection in non-array mode */
2274 if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_CONSTANT)
2275 val = value_dup (expr->constant.value);
2276 else if (eval_pos_is_array_context (ep) ||
2277 GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_FUNCALL ||
2278 GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_RANGE_CTOR ||
2279 GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_INTERSECT)
2280 val = gnm_expr_eval (expr, ep,
2281 GNM_EXPR_EVAL_PERMIT_EMPTY | GNM_EXPR_EVAL_PERMIT_NON_SCALAR);
2282 else
2283 val = gnm_expr_eval (expr, ep,
2284 GNM_EXPR_EVAL_PERMIT_EMPTY);
2286 if (val == NULL)
2287 continue;
2289 if (strict && VALUE_IS_ERROR (val)) {
2290 /* Be careful not to make VALUE_TERMINATE into a real value */
2291 return val;
2294 result = function_iterate_do_value (ep, callback, callback_closure,
2295 val, strict, iter_flags);
2296 value_release (val);
2298 return result;