2 * func-builtin.c: Built in functions.
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>
25 #include <func-builtin.h>
26 #include <rangefunc.h>
29 #include <selection.h>
31 #include <expr-deriv.h>
34 #include <application.h>
35 #include <number-match.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"},
55 gnumeric_sum (GnmFuncEvalInfo
*ei
, int argc
, GnmExprConstPtr
const *argv
)
57 return float_range_function (argc
, argv
, ei
,
59 COLLECT_IGNORE_STRINGS
|
60 COLLECT_IGNORE_BOOLS
|
61 COLLECT_IGNORE_BLANKS
,
65 static GnmExpr
const *
66 gnumeric_sum_deriv (GnmFunc
*func
,
71 GnmExprList
*l
, *args
= gnm_expr_deriv_collect (expr
, ep
, info
);
74 for (l
= args
; l
; l
= l
->next
) {
75 GnmExpr
const *e
= l
->data
;
76 GnmExpr
const *d
= gnm_expr_deriv (e
, ep
, info
);
79 l
->data
= (gpointer
)d
;
87 for (l
= args
; l
; l
= l
->next
)
88 gnm_expr_free (l
->data
);
89 gnm_expr_list_free (args
);
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
}
112 range_bogusproduct (gnm_float
const *xs
, int n
, gnm_float
*res
)
115 *res
= 0; /* Severe Excel brain damange. */
118 return gnm_range_product (xs
, n
, res
);
122 gnumeric_product (GnmFuncEvalInfo
*ei
, int argc
, GnmExprConstPtr
const *argv
)
124 return float_range_function (argc
, argv
, ei
,
126 COLLECT_IGNORE_STRINGS
|
127 COLLECT_IGNORE_BOOLS
|
128 COLLECT_IGNORE_BLANKS
,
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
}
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
;
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
;
194 gnumeric_table (GnmFuncEvalInfo
*ei
, int argc
, GnmExprConstPtr
const *argv
)
196 GnmCell
*in
[3], *x_iter
, *y_iter
;
197 GnmValue
*val
[3], *res
;
199 GnmEvalPos
const *ep
= ei
->pos
;
203 /* evaluation clears the dynamic deps */
204 gnumeric_table_link (gnm_eval_info_get_func (ei
), ei
, TRUE
);
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
;
219 gnm_cellpos_init_cellref (&pos
, cr
, &ep
->eval
, ep
->sheet
);
220 in
[x
] = sheet_cell_get (ep
->sheet
, pos
.col
, pos
.row
);
222 in
[x
] = sheet_cell_fetch (ep
->sheet
, pos
.col
, pos
.row
);
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
]));
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);
238 in
[2] = sheet_cell_fetch (ep
->sheet
,
239 ep
->eval
.col
- 1, ep
->eval
.row
- 1);
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);
252 gnm_cell_eval (x_iter
);
254 GnmValue
*v0
= value_dup (x_iter
->value
);
255 value_release (in
[0]->value
);
257 dependent_queue_recalc (GNM_CELL_TO_DEP (in
[0]));
258 gnm_app_recalc_clear_caches ();
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
);
270 gnm_cell_eval (y_iter
);
272 GnmValue
*v1
= value_dup (in
[1]->value
);
273 GnmValue
*vy
= value_dup (y_iter
->value
);
274 value_release (in
[1]->value
);
276 dependent_queue_recalc (GNM_CELL_TO_DEP (in
[1]));
277 gnm_app_recalc_clear_caches ();
279 gnm_cell_eval (in
[2]);
280 value_array_set (res
, x
, y
, value_dup (in
[2]->value
));
282 gnm_cell_eval (x_iter
);
283 value_array_set (res
, x
, y
, value_dup (x_iter
->value
));
285 value_release (in
[1]->value
);
288 value_array_set (res
, x
, y
, value_dup (y_iter
->value
));
291 value_release (in
[0]->value
);
292 in
[0]->value
= value_dup (val
[0]);
296 value_release (in
[2]->value
);
299 for (x
= 0 ; x
< 2 ; 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
++) {
307 for (y
= x
+ 1; y
< 3; y
++) {
313 gboolean had_cell
= (val
[x
] != NULL
);
315 value_release (in
[x
]->value
);
316 in
[x
]->value
= val
[x
];
319 dependent_queue_recalc (GNM_CELL_TO_DEP (in
[x
]));
321 /* always assign, we still point at a released value */
323 sheet_cell_remove (ep
->sheet
, in
[x
], FALSE
, FALSE
);
326 gnm_app_recalc_clear_caches ();
330 for (x
= 0 ; x
< 3 ; x
++) {
332 gnm_cell_eval (in
[x
]);
333 value_release (val
[x
]);
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
}
357 gnumeric_if (GnmFuncEvalInfo
*ei
, GnmValue
const * const *args
)
360 int res
= value_get_as_bool (args
[0], &err
) ? 1 : 2;
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);
369 /* arg blank: default to 0. */
370 return value_new_int (0);
374 * gnumeric_if2: (skip)
377 gnumeric_if2 (GnmFuncEvalInfo
*ei
, int argc
, GnmExprConstPtr
const *argv
,
378 GnmExprEvalFlags flags
)
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
))
403 branch
= value_get_as_bool (args
[0], &err
) ? 1 : 2;
404 for (i
= 1; i
<= 2; i
++) {
406 if (i
< argc
&& i
== branch
&& !gnm_expr_is_empty (argv
[i
])) {
407 args
[i
] = gnm_expr_eval (argv
[i
], ei
->pos
, flags
);
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
]);
421 /***************************************************************************/
423 static GnmFuncHelp
const help_number_match
[] = {
424 /* Not for public consumption. */
425 { GNM_FUNC_HELP_END
}
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
;
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
);
445 v
= format_match (text
, fmt
, date_conv
);
446 if (!v
) v
= value_new_string (text
);
449 go_format_unref (fmt
);
453 /***************************************************************************/
455 static GnmFuncHelp
const help_deriv
[] = {
456 /* Not for public consumption. */
457 { GNM_FUNC_HELP_END
}
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
;
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
);
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
[] = {
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
502 help_product
, NULL
, gnumeric_product
,
504 GNM_FUNC_IMPL_STATUS_COMPLETE
,
505 GNM_FUNC_TEST_STATUS_BASIC
507 /* --- Gnumeric --- */
508 { "gnumeric_version", "",
509 help_gnumeric_version
, gnumeric_version
, NULL
,
511 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
,
512 GNM_FUNC_TEST_STATUS_EXHAUSTIVE
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
,
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
,
528 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
,
529 GNM_FUNC_TEST_STATUS_BASIC
},
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
},
540 * gnm_func_builtin_init: (skip)
543 gnm_func_builtin_init (void)
546 const char *tdomain
= GETTEXT_PACKAGE
;
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
);
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)
579 gnm_func_builtin_shutdown (void)
583 for (i
= 0; builtins
[i
].name
; i
++) {
584 GnmFunc
*func
= gnm_func_lookup (builtins
[i
].name
, NULL
);
586 g_object_unref (func
);