Update Spanish translation
[gnumeric.git] / src / func-builtin.c
blob06b671ac582976985c5da490a95bd39e83741637
1 /*
2 * func-builtin.c: Built in functions.
4 * Authors:
5 * Morten Welinder (terra@gnome.org)
6 * Jody Goldberg (jody@gnome.org)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <https://www.gnu.org/licenses/>.
21 #include <gnumeric-config.h>
22 #include <glib/gi18n-lib.h>
23 #include <gnumeric.h>
24 #include <func.h>
25 #include <func-builtin.h>
26 #include <rangefunc.h>
27 #include <collect.h>
28 #include <value.h>
29 #include <selection.h>
30 #include <expr.h>
31 #include <expr-deriv.h>
32 #include <sheet.h>
33 #include <cell.h>
34 #include <application.h>
35 #include <number-match.h>
36 #include <gutils.h>
37 #include <ranges.h>
39 /***************************************************************************/
41 static GnmFuncHelp const help_sum[] = {
42 /* xgettext : see po-functions/README.translators */
43 { GNM_FUNC_HELP_NAME, N_("SUM:sum of the given values")},
44 /* xgettext : see po-functions/README.translators */
45 { GNM_FUNC_HELP_ARG, N_("values:a list of values to add")},
46 { GNM_FUNC_HELP_DESCRIPTION, N_("SUM computes the sum of all the values and cells referenced in the argument list.")},
47 { GNM_FUNC_HELP_EXCEL, N_("This function is Excel compatible.") },
48 { GNM_FUNC_HELP_ODF, N_("This function is OpenFormula compatible.") },
49 { GNM_FUNC_HELP_EXAMPLES, "=SUM(11,15,17,21,43)" },
50 { GNM_FUNC_HELP_SEEALSO, "AVERAGE,COUNT"},
51 { GNM_FUNC_HELP_END }
54 static GnmValue *
55 gnumeric_sum (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
57 return float_range_function (argc, argv, ei,
58 gnm_range_sum,
59 COLLECT_IGNORE_STRINGS |
60 COLLECT_IGNORE_BOOLS |
61 COLLECT_IGNORE_BLANKS,
62 GNM_ERROR_VALUE);
65 static GnmExpr const *
66 gnumeric_sum_deriv (GnmFunc *func,
67 GnmExpr const *expr,
68 GnmEvalPos const *ep,
69 GnmExprDeriv *info)
71 GnmExprList *l, *args = gnm_expr_deriv_collect (expr, ep, info);
72 gboolean bad = FALSE;
74 for (l = args; l; l = l->next) {
75 GnmExpr const *e = l->data;
76 GnmExpr const *d = gnm_expr_deriv (e, ep, info);
77 if (d) {
78 gnm_expr_free (e);
79 l->data = (gpointer)d;
80 } else {
81 bad = TRUE;
82 break;
86 if (bad) {
87 for (l = args; l; l = l->next)
88 gnm_expr_free (l->data);
89 gnm_expr_list_free (args);
90 return NULL;
91 } else
92 return gnm_expr_new_funcall (func, args);
95 /***************************************************************************/
97 static GnmFuncHelp const help_product[] = {
98 /* xgettext : see po-functions/README.translators */
99 { GNM_FUNC_HELP_NAME, N_("PRODUCT:product of the given values")},
100 /* xgettext : see po-functions/README.translators */
101 { GNM_FUNC_HELP_ARG, N_("values:a list of values to multiply")},
102 { GNM_FUNC_HELP_DESCRIPTION, N_("PRODUCT computes the product of all the values and cells referenced in the argument list.")},
103 { GNM_FUNC_HELP_NOTE, N_("If all cells are empty, the result will be 0.") },
104 { GNM_FUNC_HELP_EXCEL, N_("This function is Excel compatible.") },
105 { GNM_FUNC_HELP_ODF, N_("This function is OpenFormula compatible.") },
106 { GNM_FUNC_HELP_EXAMPLES, "=PRODUCT(2,5,9)" },
107 { GNM_FUNC_HELP_SEEALSO, "SUM,COUNT,G_PRODUCT"},
108 { GNM_FUNC_HELP_END }
111 static int
112 range_bogusproduct (gnm_float const *xs, int n, gnm_float *res)
114 if (n == 0) {
115 *res = 0; /* Severe Excel brain damange. */
116 return 0;
117 } else
118 return gnm_range_product (xs, n, res);
121 static GnmValue *
122 gnumeric_product (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
124 return float_range_function (argc, argv, ei,
125 range_bogusproduct,
126 COLLECT_IGNORE_STRINGS |
127 COLLECT_IGNORE_BOOLS |
128 COLLECT_IGNORE_BLANKS,
129 GNM_ERROR_VALUE);
132 /***************************************************************************/
134 static GnmFuncHelp const help_gnumeric_version[] = {
135 /* xgettext : see po-functions/README.translators */
136 { GNM_FUNC_HELP_NAME, N_("GNUMERIC_VERSION:the current version of Gnumeric")},
137 { GNM_FUNC_HELP_DESCRIPTION, N_("GNUMERIC_VERSION returns the version of gnumeric as a string.")},
138 { GNM_FUNC_HELP_EXAMPLES, "=GNUMERIC_VERSION()" },
139 { GNM_FUNC_HELP_SEEALSO, ""},
140 { GNM_FUNC_HELP_END }
143 static GnmValue *
144 gnumeric_version (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
146 return value_new_string (GNM_VERSION_FULL);
149 /***************************************************************************/
151 static GnmFuncHelp const help_table[] = {
152 { GNM_FUNC_HELP_NAME, N_("TABLE:internal function for data tables")},
153 { GNM_FUNC_HELP_DESCRIPTION, N_("This function should not be called directly.")},
154 { GNM_FUNC_HELP_SEEALSO, ""},
155 { GNM_FUNC_HELP_END }
159 static int //GnmDependentFlags
160 gnumeric_table_link (const GnmFunc *func, GnmFuncEvalInfo *ei, gboolean qlink)
162 GnmDependent *dep = ei->pos->dep;
163 GnmRangeRef rr;
164 int cols, rows;
166 if (!qlink)
167 return DEPENDENT_NO_FLAG;
169 if (!eval_pos_is_array_context (ei->pos))
170 return DEPENDENT_IGNORE_ARGS;
172 gnm_expr_top_get_array_size (ei->pos->array_texpr, &cols, &rows);
174 rr.a.col_relative = rr.a.row_relative =
175 rr.b.col_relative = rr.b.row_relative = FALSE;
176 rr.a.sheet = rr.b.sheet = dep->sheet;
178 g_return_val_if_fail (ei->pos->eval.col > 0, DEPENDENT_IGNORE_ARGS);
179 rr.a.col = rr.b.col = ei->pos->eval.col - 1;
180 rr.a.row = ei->pos->eval.row;
181 rr.b.row = rr.a.row + rows - 1;
182 dependent_add_dynamic_dep (dep, &rr);
184 g_return_val_if_fail (ei->pos->eval.row > 0, DEPENDENT_IGNORE_ARGS);
185 rr.a.row = rr.b.row = ei->pos->eval.row - 1;
186 rr.a.col = ei->pos->eval.col;
187 rr.b.col = rr.a.col + cols - 1;
188 dependent_add_dynamic_dep (dep, &rr);
190 return DEPENDENT_IGNORE_ARGS;
193 static GnmValue *
194 gnumeric_table (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
196 GnmCell *in[3], *x_iter, *y_iter;
197 GnmValue *val[3], *res;
198 GnmCellPos pos;
199 GnmEvalPos const *ep = ei->pos;
200 int x, y;
201 int cols, rows;
203 /* evaluation clears the dynamic deps */
204 gnumeric_table_link (gnm_eval_info_get_func (ei), ei, TRUE);
206 if (argc != 2 ||
207 ep->eval.col < 1 ||
208 ep->eval.row < 1 ||
209 !eval_pos_is_array_context (ep))
210 return value_new_error_REF (ep);
212 for (x = 0; x < 2 ; x++) {
213 GnmExpr const *arg = argv[x];
214 GnmCellRef const *cr = arg ? gnm_expr_get_cellref (arg) : NULL;
215 in[x] = NULL;
216 val[x] = NULL;
218 if (cr) {
219 gnm_cellpos_init_cellref (&pos, cr, &ep->eval, ep->sheet);
220 in[x] = sheet_cell_get (ep->sheet, pos.col, pos.row);
221 if (NULL == in[x])
222 in[x] = sheet_cell_fetch (ep->sheet, pos.col, pos.row);
223 else {
224 val[x] = value_dup (in[x]->value);
225 if (gnm_cell_has_expr (in[x]) &&
226 gnm_cell_expr_is_linked (in[x]))
227 dependent_unlink (GNM_CELL_TO_DEP (in[x]));
232 in[2] = NULL;
233 val[2] = NULL;
234 if (NULL != in[0] && NULL != in[1]) {
235 in[2] = sheet_cell_get (ep->sheet,
236 ep->eval.col - 1, ep->eval.row - 1);
237 if (NULL == in[2])
238 in[2] = sheet_cell_fetch (ep->sheet,
239 ep->eval.col - 1, ep->eval.row - 1);
240 else
241 val[2] = value_dup (in[2]->value);
244 gnm_expr_top_get_array_size (ei->pos->array_texpr, &cols, &rows);
246 res = value_new_array (cols, rows);
247 for (x = cols ; x-- > 0 ; ) {
248 x_iter = sheet_cell_get (ep->sheet,
249 x + ep->eval.col, ep->eval.row-1);
250 if (NULL == x_iter)
251 continue;
252 gnm_cell_eval (x_iter);
253 if (NULL != in[0]) {
254 GnmValue *v0 = value_dup (x_iter->value);
255 value_release (in[0]->value);
256 in[0]->value = v0;
257 dependent_queue_recalc (GNM_CELL_TO_DEP (in[0]));
258 gnm_app_recalc_clear_caches ();
259 } else {
260 value_release (val[0]);
261 val[0] = value_dup (x_iter->value);
264 for (y = rows ; y-- > 0 ; ) {
265 g_signal_emit_by_name (gnm_app_get_app (), "recalc-finished");
266 y_iter = sheet_cell_get (ep->sheet,
267 ep->eval.col-1, y + ep->eval.row);
268 if (NULL == y_iter)
269 continue;
270 gnm_cell_eval (y_iter);
271 if (NULL != in[1]) {
272 GnmValue *v1 = value_dup (in[1]->value);
273 GnmValue *vy = value_dup (y_iter->value);
274 value_release (in[1]->value);
275 in[1]->value = vy;
276 dependent_queue_recalc (GNM_CELL_TO_DEP (in[1]));
277 gnm_app_recalc_clear_caches ();
278 if (NULL != in[0]) {
279 gnm_cell_eval (in[2]);
280 value_array_set (res, x, y, value_dup (in[2]->value));
281 } else {
282 gnm_cell_eval (x_iter);
283 value_array_set (res, x, y, value_dup (x_iter->value));
285 value_release (in[1]->value);
286 in[1]->value = v1;
287 } else
288 value_array_set (res, x, y, value_dup (y_iter->value));
290 if (in[0]) {
291 value_release (in[0]->value);
292 in[0]->value = value_dup (val[0]);
295 if (NULL != in[2]) {
296 value_release (in[2]->value);
297 in[2]->value = NULL;
299 for (x = 0 ; x < 2 ; x++)
300 if (in[x] &&
301 gnm_cell_has_expr (in[x]) &&
302 !gnm_cell_expr_is_linked (in[x]))
303 dependent_link (&in[x]->base);
305 for (x = 0 ; x < 3 ; x++) {
306 int y;
307 for (y = x + 1; y < 3; y++) {
308 if (in[x] == in[y])
309 in[y] = NULL;
312 if (in[x]) {
313 gboolean had_cell = (val[x] != NULL);
315 value_release (in[x]->value);
316 in[x]->value = val[x];
317 val[x] = NULL;
319 dependent_queue_recalc (GNM_CELL_TO_DEP (in[x]));
321 /* always assign, we still point at a released value */
322 if (!had_cell) {
323 sheet_cell_remove (ep->sheet, in[x], FALSE, FALSE);
324 in[x] = NULL;
326 gnm_app_recalc_clear_caches ();
330 for (x = 0 ; x < 3 ; x++) {
331 if (in[x])
332 gnm_cell_eval (in[x]);
333 value_release (val[x]);
336 return res;
339 /***************************************************************************/
341 static GnmFuncHelp const help_if[] = {
342 /* xgettext : see po-functions/README.translators */
343 { GNM_FUNC_HELP_NAME, N_("IF:conditional expression") },
344 /* xgettext : see po-functions/README.translators */
345 { GNM_FUNC_HELP_ARG, N_("cond:condition") },
346 /* xgettext : see po-functions/README.translators */
347 { GNM_FUNC_HELP_ARG, N_("trueval:value to use if condition is true") },
348 /* xgettext : see po-functions/README.translators */
349 { GNM_FUNC_HELP_ARG, N_("falseval:value to use if condition is false") },
350 { GNM_FUNC_HELP_DESCRIPTION, N_("This function first evaluates the condition. If the result is true, it will then evaluate and return the second argument. Otherwise, it will evaluate and return the last argument.") },
351 { GNM_FUNC_HELP_EXAMPLES, "=IF(1+2=3,\"x\",\"y\")" },
352 { GNM_FUNC_HELP_SEEALSO, "AND,OR,XOR,NOT,IFERROR" },
353 { GNM_FUNC_HELP_END }
356 static GnmValue *
357 gnumeric_if (GnmFuncEvalInfo *ei, GnmValue const * const *args)
359 gboolean err;
360 int res = value_get_as_bool (args[0], &err) ? 1 : 2;
362 if (args[res])
363 return value_dup (args[res]);
365 if (gnm_eval_info_get_arg_count (ei) < res + 1)
366 /* arg-not-there: default to TRUE/FALSE. */
367 return value_new_bool (res == 1);
368 else
369 /* arg blank: default to 0. */
370 return value_new_int (0);
374 * gnumeric_if2: (skip)
376 GnmValue *
377 gnumeric_if2 (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv,
378 GnmExprEvalFlags flags)
380 gboolean err;
381 int i, branch;
382 GnmValue *args[3];
383 GnmValue *res;
385 g_return_val_if_fail (argc >= 1 && argc <= 3,
386 value_new_error_VALUE (ei->pos));
389 * In this version of IF, we evaluate the arguments ourselves,
390 * then call the regular IF. However, arguments we do not need
391 * we do not evaluate.
393 * IF is sometimes used to avoid expensive calculations. Always
394 * computing both branches destroys that intent. See bug 326595.
397 /* Evaluate condition. */
398 res = gnm_expr_eval (argv[0], ei->pos, 0);
399 if (VALUE_IS_ERROR (res))
400 return res;
401 args[0] = res;
403 branch = value_get_as_bool (args[0], &err) ? 1 : 2;
404 for (i = 1; i <= 2; i++) {
405 args[i] = NULL;
406 if (i < argc && i == branch && !gnm_expr_is_empty (argv[i])) {
407 args[i] = gnm_expr_eval (argv[i], ei->pos, flags);
408 if (!args[i])
409 args[i] = value_new_empty ();
413 res = gnumeric_if (ei, (GnmValue const * const *)args);
415 for (i = 0; i <= 2; i++)
416 value_release (args[i]);
418 return res;
421 /***************************************************************************/
423 static GnmFuncHelp const help_number_match[] = {
424 /* Not for public consumption. */
425 { GNM_FUNC_HELP_END }
428 static GnmValue *
429 gnumeric_number_match (GnmFuncEvalInfo *ei, GnmValue const * const *args)
431 const char *text = value_peek_string (args[0]);
432 const char *fmttxt = args[1] ? value_peek_string (args[1]) : NULL;
433 GOFormat *fmt = NULL;
434 GnmValue *v;
435 GODateConventions const *date_conv = NULL;
437 if (fmttxt && *fmttxt != 0) {
438 fmt = go_format_new_from_XL (fmttxt);
439 if (go_format_is_invalid (fmt)) {
440 v = value_new_error_VALUE (ei->pos);
441 goto out;
445 v = format_match (text, fmt, date_conv);
446 if (!v) v = value_new_string (text);
448 out:
449 go_format_unref (fmt);
450 return v;
453 /***************************************************************************/
455 static GnmFuncHelp const help_deriv[] = {
456 /* Not for public consumption. */
457 { GNM_FUNC_HELP_END }
460 static GnmValue *
461 gnumeric_deriv (GnmFuncEvalInfo *ei, GnmValue const * const *args)
463 GnmValue const *vy = args[0];
464 GnmValue const *vx = args[1];
465 Sheet *sy, *sy2, *sx, *sx2;
466 GnmRange ry, rx;
467 GnmCell *cy, *cx;
469 if (!VALUE_IS_CELLRANGE (vy) ||
470 !VALUE_IS_CELLRANGE (vx))
471 return value_new_error_VALUE (ei->pos);
473 gnm_rangeref_normalize (value_get_rangeref (vy), ei->pos, &sy, &sy2, &ry);
474 gnm_rangeref_normalize (value_get_rangeref (vx), ei->pos, &sx, &sx2, &rx);
475 if (!range_is_singleton (&ry) || sy2 != sy ||
476 !range_is_singleton (&rx) || sx2 != sx)
477 return value_new_error_VALUE (ei->pos);
479 cy = sheet_cell_get (sy, ry.start.col, ry.start.row);
480 cx = sheet_cell_get (sx, rx.start.col, rx.start.row);
481 if (!cy || !cx)
482 return value_new_error_VALUE (ei->pos);
484 return value_new_float (gnm_expr_cell_deriv_value (cy, cx));
487 /***************************************************************************/
489 static GnmFuncGroup *math_group = NULL;
490 static GnmFuncGroup *gnumeric_group = NULL;
491 static GnmFuncGroup *logic_group = NULL;
493 static GnmFuncDescriptor const builtins [] = {
494 /* --- Math --- */
495 { "sum", NULL,
496 help_sum, NULL, gnumeric_sum,
497 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
498 GNM_FUNC_IMPL_STATUS_COMPLETE,
499 GNM_FUNC_TEST_STATUS_BASIC
501 { "product", NULL,
502 help_product, NULL, gnumeric_product,
503 GNM_FUNC_SIMPLE,
504 GNM_FUNC_IMPL_STATUS_COMPLETE,
505 GNM_FUNC_TEST_STATUS_BASIC
507 /* --- Gnumeric --- */
508 { "gnumeric_version", "",
509 help_gnumeric_version, gnumeric_version, NULL,
510 GNM_FUNC_SIMPLE,
511 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
512 GNM_FUNC_TEST_STATUS_EXHAUSTIVE
514 { "table", NULL,
515 help_table, NULL, gnumeric_table,
516 GNM_FUNC_SIMPLE + GNM_FUNC_INTERNAL,
517 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
518 GNM_FUNC_TEST_STATUS_EXHAUSTIVE
520 { "number_match", "s|s", // Only in test suite
521 help_number_match, gnumeric_number_match, NULL,
522 GNM_FUNC_INTERNAL,
523 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
524 GNM_FUNC_TEST_STATUS_BASIC },
525 { "deriv", "r|r", // Only in test suite
526 help_deriv, gnumeric_deriv, NULL,
527 GNM_FUNC_INTERNAL,
528 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
529 GNM_FUNC_TEST_STATUS_BASIC },
530 /* --- Logic --- */
531 { "if", "b|EE",
532 help_if, gnumeric_if, NULL,
533 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_SECOND,
534 GNM_FUNC_IMPL_STATUS_COMPLETE,
535 GNM_FUNC_TEST_STATUS_BASIC },
536 { NULL }
540 * gnm_func_builtin_init: (skip)
542 void
543 gnm_func_builtin_init (void)
545 const char *gname;
546 const char *tdomain = GETTEXT_PACKAGE;
547 int i = 0;
549 gname = N_("Mathematics");
550 math_group = gnm_func_group_fetch (gname, _(gname));
551 gnm_func_add (math_group, builtins + i++, tdomain);
552 gnm_func_add (math_group, builtins + i++, tdomain);
554 gname = N_("Gnumeric");
555 gnumeric_group = gnm_func_group_fetch (gname, _(gname));
556 gnm_func_add (gnumeric_group, builtins + i++, tdomain);
557 gnm_func_add (gnumeric_group, builtins + i++, tdomain);
558 if (gnm_debug_flag ("testsuite")) {
559 gnm_func_add (gnumeric_group, builtins + i, tdomain);
560 gnm_func_add (gnumeric_group, builtins + i + 1, tdomain);
562 i += 2;
564 gname = N_("Logic");
565 logic_group = gnm_func_group_fetch (gname, _(gname));
566 gnm_func_add (logic_group, builtins + i++, tdomain);
568 g_signal_connect (gnm_func_lookup ("table", NULL),
569 "link-dep", G_CALLBACK (gnumeric_table_link), NULL);
571 g_signal_connect (gnm_func_lookup ("sum", NULL),
572 "derivative", G_CALLBACK (gnumeric_sum_deriv), NULL);
576 * gnm_func_builtin_shutdown: (skip)
578 void
579 gnm_func_builtin_shutdown (void)
581 int i;
583 for (i = 0; builtins[i].name; i++) {
584 GnmFunc *func = gnm_func_lookup (builtins[i].name, NULL);
585 if (func)
586 g_object_unref (func);