1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * func.c: Function management and utility routines.
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>
18 #include "parse-util.h"
19 #include "dependent.h"
21 #include "expr-impl.h"
22 #include "expr-name.h"
24 #include "workbook-priv.h"
27 #include "number-match.h"
28 #include "func-builtin.h"
29 #include "command-context-stderr.h"
30 #include "gnm-plugin.h"
33 #include <goffice/goffice.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
;
51 g_hash_table_new (go_ascii_strcase_hash
, go_ascii_strcase_equal
);
54 functions_by_localized_name
=
55 g_hash_table_new (go_ascii_strcase_hash
, go_ascii_strcase_equal
);
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
),
69 func
->usage_count
= 0;
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
;
83 gnm_func_load_if_stub (GnmFunc
*func
)
85 if (func
->fn_type
== GNM_FUNC_TYPE_STUB
)
86 gnm_func_load_stub (func
);
90 copy_hash_table_to_ptr_array (gpointer key
, gpointer value
, gpointer array
)
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)
103 gnm_func_load_if_stub (fd
);
104 if (fd
->help
!= NULL
)
105 g_ptr_array_add (array
, fd
);
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
);
124 return g_ascii_strcasecmp (fda
->name
, fdb
->name
);
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
);
135 split_at_colon (char const *s
, char **rest
)
137 char *dup
= g_strdup (s
);
138 char *colon
= strchr (dup
, ':');
141 if (rest
) *rest
= colon
+ 1;
143 if (rest
) *rest
= NULL
;
149 dump_externals (GPtrArray
*defs
, FILE *out
)
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
;
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
:
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) {
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
);
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 :
219 * A generic utility routine to operate on all funtion defs
220 * in various ways. @dump_type will change/extend as needed
222 * 0 : www.gnumeric.org's function.shtml page
225 * 3 : dump function usage count
229 function_dump_defs (char const *filename
, int dump_type
)
235 GnmFuncGroup
const *group
= NULL
;
237 if (dump_type
== 2) {
238 g_printerr ("generate po is obsolete.\n");
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
);
248 if (dump_type
== 3) {
249 g_hash_table_foreach (functions_by_name
,
250 (GHFunc
) cb_dump_usage
,
252 fclose (output_file
);
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
),
266 if (dump_type
== 4) {
267 dump_externals (ordered
, output_file
);
268 g_ptr_array_free (ordered
, TRUE
);
269 fclose (output_file
);
273 if (dump_type
== 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
:
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"
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"
300 " table.functiongroup {\n"
301 " border-style: solid;\n"
302 " border-width: 1px;\n"
303 " border-spacing: 0px;\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"
312 " tr.function td {\n"
313 " border: solid 1px;\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"
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 — Pick Any Three!</p>\n"
335 " <img id=\"logo\" src=\"gnumeric.png\" alt=\"logo\" class=\"float-right\"/>\n"
338 " <div id=\"nav\">\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"
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) {
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
);
370 fprintf (output_file
, "@CATEGORY=%s\n",
371 F2(fd
, fd
->fn_group
->display_name
->str
));
373 fd
->help
[i
].type
!= GNM_FUNC_HELP_END
;
375 switch (fd
->help
[i
].type
) {
376 case GNM_FUNC_HELP_NAME
: {
378 char *name
= split_at_colon (F2(fd
, fd
->help
[i
].text
), &short_desc
);
379 fprintf (output_file
,
382 fprintf (output_file
,
385 g_string_append (syntax
, name
);
386 g_string_append_c (syntax
, '(');
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
));
395 case GNM_FUNC_HELP_DESCRIPTION
:
397 g_string_append (desc
, "\n");
398 g_string_append (desc
, F2(fd
, fd
->help
[i
].text
));
400 case GNM_FUNC_HELP_NOTE
:
402 g_string_append (note
, " ");
403 g_string_append (note
, F2(fd
, fd
->help
[i
].text
));
405 case GNM_FUNC_HELP_ARG
: {
407 char *name
= split_at_colon (F2(fd
, fd
->help
[i
].text
), &argdesc
);
411 g_string_append_c (syntax
, go_locale_get_arg_sep ());
412 g_string_append (syntax
, name
);
414 g_string_append_printf (arg_desc
,
420 /* FIXME: Optional args? */
423 case GNM_FUNC_HELP_ODF
:
425 g_string_append (odf
, " ");
426 g_string_append (odf
, F2(fd
, fd
->help
[i
].text
));
428 case GNM_FUNC_HELP_EXCEL
:
430 g_string_append (excel
, " ");
431 g_string_append (excel
, F2(fd
, fd
->help
[i
].text
));
434 case GNM_FUNC_HELP_EXTREF
:
436 case GNM_FUNC_HELP_EXAMPLES
:
438 case GNM_FUNC_HELP_END
:
443 function_def_count_args (fd
, &min
, &max
);
445 fprintf (output_file
,
446 "@SYNTAX=%s," UNICODE_ELLIPSIS
")\n",
449 fprintf (output_file
, "@SYNTAX=%s)\n",
452 if (arg_desc
->len
> 0)
453 fprintf (output_file
, "@ARGUMENTDESCRIPTION=%s", arg_desc
->str
);
455 fprintf (output_file
, "@DESCRIPTION=%s\n", desc
->str
);
457 fprintf (output_file
, "@NOTE=%s\n", note
->str
);
459 fprintf (output_file
, "@EXCEL=%s\n", excel
->str
);
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) {
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" }
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
,
503 "<div class=\"functiongroup\"><table class=\"functiongroup\">\n"
504 "<tr class=\"header\">"
506 "<td>Implementation</td>"
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
);
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
,
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
,
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
,
539 " <!-- MARKER: end-main -->\n"
540 " <!-- MARKER: start-sidebar -->\n"
541 " <!-- MARKER: end-sidebar -->\n"
548 g_ptr_array_free (ordered
, TRUE
);
549 fclose (output_file
);
552 /* ------------------------------------------------------------------------- */
555 check_help_expression (const char *text
, GnmFunc
const *fd
)
557 GnmConventions
const *convs
= gnm_conventions_default
;
559 GnmExprTop
const *texpr
;
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
,
574 g_printerr ("Error parsing %s: %s\n",
575 text
, perr
.err
->message
);
577 parse_error_free (&perr
);
583 gnm_expr_top_unref (texpr
);
588 check_argument_refs (const char *text
, GnmFunc
const *fd
)
590 if (fd
->fn_type
!= GNM_FUNC_TYPE_ARGS
)
594 const char *at
= strchr (text
, '@');
602 text
= strchr (at
+ 2, '}');
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
);
614 found
= strcmp (argname
, thisarg
) == 0;
625 gnm_func_sanity_check1 (GnmFunc
const *fd
)
627 GnmFuncHelp
const *h
;
628 int counts
[(int)GNM_FUNC_HELP_ODF
+ 1];
630 size_t nlen
= strlen (fd
->name
);
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
);
641 if (!g_utf8_validate (h
->text
, -1, NULL
)) {
642 g_printerr ("%s: Invalid UTF-8 in type %i\n",
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",
655 } else if (h
->text
[nlen
+ 1] == ' ') {
656 g_printerr ("%s: Unwanted space in NAME record\n",
659 } else if (h
->text
[strlen (h
->text
) - 1] == '.') {
660 g_printerr ("%s: Unwanted period in NAME record\n",
665 case GNM_FUNC_HELP_ARG
: {
666 const char *aend
= strchr (h
->text
, ':');
669 if (aend
== NULL
|| aend
== h
->text
) {
670 g_printerr ("%s: Invalid ARG record\n",
676 if (aend
[1] == ' ') {
677 g_printerr ("%s: Unwanted space in ARG record\n",
681 if (aend
[1] == '\0') {
682 g_printerr ("%s: Empty ARG record\n",
686 if (h
->text
[strlen (h
->text
) - 1] == '.') {
687 g_printerr ("%s: Unwanted period in ARG record\n",
691 if (check_argument_refs (aend
+ 1, fd
)) {
692 g_printerr ("%s: Invalid argument reference in argument\n",
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",
702 g_printerr ("%s\n", h
->text
);
704 g_hash_table_insert (allargs
, argname
, argname
);
707 case GNM_FUNC_HELP_DESCRIPTION
: {
710 if (check_argument_refs (h
->text
, fd
)) {
711 g_printerr ("%s: Invalid argument reference in description\n",
717 while (g_ascii_isupper (*p
) ||
718 (p
!= h
->text
&& (*p
== '_' ||
720 g_ascii_isdigit (*p
))))
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",
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",
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",
755 fd
->fn
.args
.min_args
, fd
->fn
.args
.max_args
);
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
]);
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
]);
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
]);
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
]);
790 gnm_func_sanity_check (void)
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
),
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
))
810 g_ptr_array_free (ordered
, TRUE
);
815 /* ------------------------------------------------------------------------- */
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)
826 go_string_unref (fn_group
->internal_name
);
827 go_string_unref (fn_group
->display_name
);
831 static GnmFuncGroup
*
832 gnm_func_group_ref (GnmFuncGroup
*fn_group
)
834 fn_group
->ref_count
++;
839 gnm_func_group_get_type (void)
844 t
= g_boxed_type_register_static ("GnmFuncGroup",
845 (GBoxedCopyFunc
)gnm_func_group_ref
,
846 (GBoxedFreeFunc
)gnm_func_group_free
);
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
);
861 gnm_func_group_fetch (char const *name
, char const *translation
)
863 GnmFuncGroup
*cat
= NULL
;
866 g_return_val_if_fail (name
!= NULL
, NULL
);
868 for (l
= categories
; l
!= NULL
; l
= l
->next
) {
870 if (strcmp (cat
->internal_name
->str
, name
) == 0) {
876 cat
= g_new (GnmFuncGroup
, 1);
877 cat
->internal_name
= go_string_new (name
);
879 if (translation
!= NULL
) {
880 cat
->display_name
= go_string_new (translation
);
881 cat
->has_translation
= TRUE
;
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
);
896 categories
= g_list_insert_sorted (
897 categories
, cat
, &function_category_compare
);
904 gnm_func_group_get_nth (int n
)
906 return g_list_nth_data (categories
, n
);
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
);
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
)
929 gnm_func_group_free (fn_group
);
933 /******************************************************************************/
936 extract_arg_types (GnmFunc
*def
)
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;
950 error_function_no_full_info (GnmFuncEvalInfo
*ei
,
952 GnmExprConstPtr
const *argv
)
954 return value_new_error (ei
->pos
, _("Function implementation not available."));
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
;
968 gnm_func_create_arg_names (GnmFunc
*fn_def
)
973 g_return_if_fail (fn_def
!= NULL
);
975 ptr
= g_ptr_array_new ();
977 fn_def
->help
&& fn_def
->help
[i
].type
!= GNM_FUNC_HELP_END
;
979 if (fn_def
->help
[i
].type
!= GNM_FUNC_HELP_ARG
)
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
;
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
;
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
);
1023 func
->fn_type
= GNM_FUNC_TYPE_NODES
;
1024 func
->fn
.nodes
= &error_function_no_full_info
;
1025 func
->linker
= NULL
;
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
);
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
;
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
);
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);
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);
1098 gnm_func_get_type (void)
1103 t
= g_boxed_type_register_static ("GnmFunc",
1104 (GBoxedCopyFunc
)gnm_func_ref
,
1105 (GBoxedFreeFunc
)gnm_func_unref
);
1111 gnm_func_lookup (char const *name
, Workbook
*scope
)
1113 GnmFunc
*fd
= g_hash_table_lookup (functions_by_name
, name
);
1116 if (scope
== NULL
|| scope
->sheet_local_functions
== NULL
)
1118 return g_hash_table_lookup (scope
->sheet_local_functions
, (gpointer
)name
);
1122 gnm_func_lookup_localized (char const *name
, Workbook
*scope
)
1125 GHashTableIter hiter
;
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
);
1138 if (scope
== NULL
|| scope
->sheet_local_functions
== NULL
)
1140 return g_hash_table_lookup (scope
->sheet_local_functions
, (gpointer
)name
);
1144 * gnm_func_lookup_prefix:
1145 * @prefix: prefix to search for
1147 * @trans: whether to search translated function names
1149 * Returns: (element-type GnmFunc*) (transfer full):
1152 gnm_func_lookup_prefix (char const *prefix
, Workbook
*scope
, gboolean trans
)
1155 GHashTableIter hiter
;
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
)) {
1169 res
= g_slist_prepend (res
, fd
);
1178 gnm_func_add (GnmFuncGroup
*fn_group
,
1179 GnmFuncDescriptor
const *desc
,
1180 const char *textdomain
)
1182 static char const valid_tokens
[] = "fsbraAES?|";
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);
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
;
1227 g_warning ("Invalid function has neither args nor nodes handler");
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
);
1244 /* Handle unknown functions on import without losing their names */
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:
1258 * @load_desc: (scope async):
1259 * @opt_usage_notify: (scope async):
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
);
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
);
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
)) {
1303 name
= g_strdup_printf (template, count
);
1310 gnm_func_add_placeholder_full (Workbook
*scope
,
1311 char const *gname
, char const *lname
,
1314 GnmFuncDescriptor desc
;
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
);
1325 unknown_cat
= gnm_func_group_fetch
1326 (unknown_cat_name
, _(unknown_cat_name
));
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");
1339 /* xgettext: This represents a made-up translated function name. */
1340 lname
= invent_name (gname
, functions_by_localized_name
, _("unknown%d"));
1344 if (gnm_debug_flag ("func"))
1345 g_printerr ("Adding placeholder for %s (aka %s)\n", gname
, lname
);
1347 memset (&desc
, 0, sizeof (GnmFuncDescriptor
));
1349 desc
.arg_spec
= NULL
;
1351 desc
.fn_args
= NULL
;
1352 desc
.fn_nodes
= &unknownFunctionHandler
;
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
;
1360 desc
.flags
|= GNM_FUNC_IS_WORKBOOK_LOCAL
;
1363 /* WISHLIST : it would be nice to have a log if these. */
1364 g_warning ("Unknown %s function : %s", type
, desc
.name
);
1368 func
= gnm_func_add (unknown_cat
, &desc
, NULL
);
1371 gnm_func_set_localized_name (func
, lname
);
1373 g_free ((char *)lname
);
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
);
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
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
);
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 */
1414 gnm_func_lookup_or_add_placeholder (char const *name
)
1416 GnmFunc
* f
= gnm_func_lookup (name
, NULL
);
1418 f
= gnm_func_add_placeholder (NULL
, name
, "");
1423 * gnm_func_get_user_data:
1426 * Returns: (transfer none):
1429 gnm_func_get_user_data (GnmFunc
const *func
)
1431 g_return_val_if_fail (func
!= NULL
, NULL
);
1433 return func
->user_data
;
1437 gnm_func_set_user_data (GnmFunc
*func
, gpointer user_data
)
1439 g_return_if_fail (func
!= NULL
);
1441 func
->user_data
= user_data
;
1445 gnm_func_get_name (GnmFunc
const *func
, gboolean localized_function_names
)
1448 GnmFunc
*fd
= (GnmFunc
*)func
;
1450 g_return_val_if_fail (func
!= NULL
, NULL
);
1452 if (!localized_function_names
)
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
1464 gnm_func_load_if_stub (fd
);
1467 (func
->localized_name
== NULL
&&
1469 func
->help
[i
].type
!= GNM_FUNC_HELP_END
);
1473 if (func
->help
[i
].type
!= GNM_FUNC_HELP_NAME
)
1476 s
= func
->help
[i
].text
;
1478 if (s
== sl
) /* String not actually translated. */
1481 U
= split_at_colon (F2 (func
, s
), NULL
);
1483 char *lname
= g_utf8_strdown (U
, -1);
1484 gnm_func_set_localized_name (fd
, lname
);
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
1504 gnm_func_get_description (GnmFunc
const *fn_def
)
1507 g_return_val_if_fail (fn_def
!= NULL
, NULL
);
1509 gnm_func_load_if_stub ((GnmFunc
*)fn_def
);
1512 fn_def
->help
&& fn_def
->help
[i
].type
!= GNM_FUNC_HELP_END
;
1516 if (fn_def
->help
[i
].type
!= GNM_FUNC_HELP_NAME
)
1519 desc
= strchr (F2 (fn_def
, fn_def
->help
[i
].text
), ':');
1520 return desc
? (desc
+ 1) : "";
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
1539 function_def_count_args (GnmFunc
const *fn_def
,
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
) {
1558 if (g_ascii_strcasecmp ("INDEX",fn_def
->name
) == 0)
1565 ptr
= fn_def
->fn
.args
.arg_spec
;
1566 for (i
= vararg
= 0; ptr
&& *ptr
; ptr
++) {
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
1586 function_def_get_arg_type (GnmFunc
const *fn_def
, int arg_idx
)
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
++) {
1605 case GNM_FUNC_TYPE_NODES
:
1606 return '?'; /* Close enough for now. */
1608 case GNM_FUNC_TYPE_STUB
:
1609 #ifndef DEBUG_SWITCH_ENUM
1612 g_assert_not_reached ();
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
1625 function_def_get_arg_type_string (GnmFunc
const *fn_def
,
1628 switch (function_def_get_arg_type (fn_def
, arg_idx
)) {
1634 return _("Boolean");
1636 return _("Cell Range");
1640 return _("Scalar, Blank, or Error");
1644 /* Missing values will be NULL. */
1648 g_warning ("Unknown arg type");
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)
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
,
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
1682 gnm_func_get_arg_description (GnmFunc
const *fn_def
, guint arg_idx
)
1685 g_return_val_if_fail (fn_def
!= NULL
, NULL
);
1687 gnm_func_load_if_stub ((GnmFunc
*)fn_def
);
1690 fn_def
->help
&& fn_def
->help
[i
].type
!= GNM_FUNC_HELP_END
;
1694 if (fn_def
->help
[i
].type
!= GNM_FUNC_HELP_ARG
)
1699 desc
= strchr (F2 (fn_def
, fn_def
->help
[i
].text
), ':');
1704 while (g_unichar_isspace (g_utf8_get_char (desc
)))
1705 desc
= g_utf8_next_char (desc
);
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
1721 gnm_func_convert_markup_to_pango (char const *desc
, GtkWidget
*target
)
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\">",
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
);
1741 while ((at
= strstr (str
->str
, "@{"))) {
1742 gint len
= at
- str
->str
;
1743 go_string_replace (str
, len
, 2, span_text
, -1);
1745 (str
->str
+ len
+ span_text_len
, "}"))) {
1746 len
= at
- str
->str
;
1747 go_string_replace (str
, len
, 1, "</span>", -1);
1749 g_string_append (str
, "</span>");
1753 return g_string_free (str
, FALSE
);
1757 /* ------------------------------------------------------------------------- */
1760 free_values (GnmValue
**values
, int top
)
1764 for (i
= 0; i
< top
; 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.
1780 function_call_with_exprs (GnmFuncEvalInfo
*ei
)
1782 GnmFunc
const *fn_def
;
1783 int i
, iter_count
, iter_width
= 0, iter_height
= 0;
1785 GnmValue
**args
, *tmp
= NULL
;
1786 int *iter_item
= NULL
;
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
);
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
))
1816 /* Optimization for IF when implicit iteration is not used. */
1817 if (ei
->func_call
->func
->fn
.args
.func
== gnumeric_if
&&
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
1828 GnmExpr
const *expr
= argv
[i
];
1830 if (arg_type
== 'A' || arg_type
== 'r') {
1831 tmp
= args
[i
] = gnm_expr_eval
1834 GNM_EXPR_EVAL_PERMIT_NON_SCALAR
|
1835 GNM_EXPR_EVAL_WANT_REF
);
1836 if (VALUE_IS_ERROR (tmp
)) {
1837 free_values (args
, i
);
1841 if (tmp
->type
== VALUE_CELLRANGE
) {
1842 gnm_cellref_make_abs (&tmp
->v_range
.cell
.a
,
1843 &tmp
->v_range
.cell
.a
,
1845 gnm_cellref_make_abs (&tmp
->v_range
.cell
.b
,
1846 &tmp
->v_range
.cell
.b
,
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
);
1856 /* force scalars whenever we are certain */
1857 tmp
= args
[i
] = gnm_expr_eval
1860 GNM_EXPR_EVAL_PERMIT_EMPTY
|
1861 (iter_count
>= 0 || arg_type
== '?'
1862 ? GNM_EXPR_EVAL_PERMIT_NON_SCALAR
1865 if (arg_type
== '?') /* '?' arguments are unrestriced */
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 ();
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
);
1891 if (iter_count
< 0) {
1892 g_warning ("Damn I thought this was impossible");
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" */
1905 /* All of these argument types must be scalars */
1908 if (VALUE_IS_STRING (tmp
)) {
1910 gboolean b
= value_get_as_bool (tmp
, &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
);
1921 if (VALUE_IS_STRING (tmp
)) {
1922 tmp
= format_match_number (value_peek_string (tmp
), NULL
,
1923 workbook_date_conv (ei
->pos
->sheet
->workbook
));
1925 free_values (args
, i
+ 1);
1926 return value_new_error_VALUE (ei
->pos
);
1928 value_release (args
[i
]);
1930 } else if (VALUE_IS_ERROR (tmp
)) {
1931 free_values (args
, i
);
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
);
1944 if (VALUE_IS_ERROR (tmp
)) {
1945 free_values (args
, i
);
1950 case 'E': /* nothing necessary */
1953 /* case '?': handled above */
1955 g_warning ("Unknown argument type '%c'", arg_type
);
1960 while (i
< fn_def
->fn
.args
.max_args
)
1963 if (iter_item
!= NULL
) {
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 */
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
))
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
));
1988 args
[iter_item
[i
]] = iter_args
[i
] = tmp
;
1992 } else if (VALUE_IS_ERROR (elem
)) {
1995 } else if (!VALUE_IS_NUMBER (elem
))
1997 } else if (arg_type
== 's') {
1998 if (VALUE_IS_EMPTY (elem
)) {
1999 args
[iter_item
[i
]] = iter_args
[i
] = value_new_string ("");
2001 } else if (VALUE_IS_ERROR (elem
)) {
2004 } else if (!VALUE_IS_STRING (elem
))
2006 } else if (elem
== NULL
) {
2007 args
[iter_item
[i
]] = iter_args
[i
] = value_new_empty ();
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
];
2024 i
= fn_def
->fn
.args
.max_args
;
2026 tmp
= fn_def
->fn
.args
.func (ei
, (GnmValue
const * const *)args
);
2028 free_values (args
, i
);
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
2037 function_call_with_values (GnmEvalPos
const *ep
, char const *fn_name
,
2038 int argc
, GnmValue
const * const *values
)
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
);
2049 return value_new_error_NAME (ep
);
2050 return function_def_call_with_values (ep
, fn_def
, argc
, values
);
2054 function_def_call_with_values (GnmEvalPos
const *ep
, GnmFunc
const *fn_def
,
2055 int argc
, GnmValue
const * const *values
)
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
);
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
);
2084 retval
= fn_def
->fn
.args
.func (&fs
, values
);
2089 /* ------------------------------------------------------------------------- */
2092 FunctionIterateCB callback
;
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.
2105 cb_iterate_cellrange (GnmCellIter
const *iter
, gpointer user
)
2108 IterateCallbackClosure
*data
= user
;
2113 if (NULL
== (cell
= iter
->cell
)) {
2114 ep
.sheet
= iter
->pp
.sheet
;
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
))
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.
2142 function_iterate_do_value (GnmEvalPos
const *ep
,
2143 FunctionIterateCB callback
,
2145 GnmValue
const *value
,
2147 CellIterFlags iter_flags
)
2149 GnmValue
*res
= NULL
;
2151 switch (value
->type
){
2154 res
= value_dup (value
);
2163 res
= (*callback
)(ep
, value
, closure
);
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
);
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
,
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.
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).
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).
2223 function_iterate_argument_values (GnmEvalPos
const *ep
,
2224 FunctionIterateCB callback
,
2225 void *callback_closure
,
2227 GnmExprConstPtr
const *argv
,
2229 CellIterFlags iter_flags
)
2231 GnmValue
*result
= NULL
;
2234 for (a
= 0; result
== NULL
&& a
< argc
; a
++) {
2235 GnmExpr
const *expr
= argv
[a
];
2238 if (iter_flags
& CELL_ITER_IGNORE_SUBTOTAL
&&
2239 gnm_expr_contains_subtotal (expr
))
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
;
2248 return value_new_error_REF (ep
);
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
);
2262 /* We need a cleaner model of what to do here.
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)
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
);
2283 val
= gnm_expr_eval (expr
, ep
,
2284 GNM_EXPR_EVAL_PERMIT_EMPTY
);
2289 if (strict
&& VALUE_IS_ERROR (val
)) {
2290 /* Be careful not to make VALUE_TERMINATE into a real value */
2294 result
= function_iterate_do_value (ep
, callback
, callback_closure
,
2295 val
, strict
, iter_flags
);
2296 value_release (val
);