1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * func-builtin.c: Built in functions.
6 * Morten Welinder (terra@gnome.org)
7 * Jody Goldberg (jody@gnome.org)
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <https://www.gnu.org/licenses/>.
22 #include <gnumeric-config.h>
23 #include <glib/gi18n-lib.h>
26 #include <func-builtin.h>
27 #include <rangefunc.h>
30 #include <selection.h>
32 #include <expr-deriv.h>
35 #include <application.h>
36 #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 (GnmExpr
const *expr
,
70 GnmExprList
*l
, *args
= gnm_expr_deriv_collect (expr
, ep
, info
);
71 GnmFunc
*fsum
= gnm_expr_get_func_def (expr
);
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 (fsum
, 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 GnmDependentFlags
160 gnumeric_table_link (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 (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);
375 gnumeric_if2 (GnmFuncEvalInfo
*ei
, int argc
, GnmExprConstPtr
const *argv
,
376 GnmExprEvalFlags flags
)
383 g_return_val_if_fail (argc
>= 1 && argc
<= 3,
384 value_new_error_VALUE (ei
->pos
));
387 * In this version of IF, we evaluate the arguments ourselves,
388 * then call the regular IF. However, arguments we do not need
389 * we do not evaluate.
391 * IF is sometimes used to avoid expensive calculations. Always
392 * computing both branches destroys that intent. See bug 326595.
395 /* Evaluate condition. */
396 res
= gnm_expr_eval (argv
[0], ei
->pos
, 0);
397 if (VALUE_IS_ERROR (res
))
401 branch
= value_get_as_bool (args
[0], &err
) ? 1 : 2;
402 for (i
= 1; i
<= 2; i
++) {
404 if (i
< argc
&& i
== branch
&& !gnm_expr_is_empty (argv
[i
])) {
405 args
[i
] = gnm_expr_eval (argv
[i
], ei
->pos
, flags
);
407 args
[i
] = value_new_empty ();
411 res
= gnumeric_if (ei
, (GnmValue
const * const *)args
);
413 for (i
= 0; i
<= 2; i
++)
414 value_release (args
[i
]);
419 /***************************************************************************/
421 static GnmFuncHelp
const help_number_match
[] = {
422 /* Not for public consumption. */
423 { GNM_FUNC_HELP_END
}
427 gnumeric_number_match (GnmFuncEvalInfo
*ei
, GnmValue
const * const *args
)
429 const char *text
= value_peek_string (args
[0]);
430 const char *fmttxt
= args
[1] ? value_peek_string (args
[1]) : NULL
;
431 GOFormat
*fmt
= NULL
;
433 GODateConventions
const *date_conv
= NULL
;
435 if (fmttxt
&& *fmttxt
!= 0) {
436 fmt
= go_format_new_from_XL (fmttxt
);
437 if (go_format_is_invalid (fmt
)) {
438 v
= value_new_error_VALUE (ei
->pos
);
443 v
= format_match (text
, fmt
, date_conv
);
444 if (!v
) v
= value_new_string (text
);
447 go_format_unref (fmt
);
451 /***************************************************************************/
453 static GnmFuncGroup
*math_group
= NULL
;
454 static GnmFuncGroup
*gnumeric_group
= NULL
;
455 static GnmFuncGroup
*logic_group
= NULL
;
458 func_builtin_init (void)
461 const char *tdomain
= GETTEXT_PACKAGE
;
464 static GnmFuncDescriptor
const builtins
[] = {
467 help_sum
, NULL
, gnumeric_sum
,
468 NULL
, NULL
, GNM_FUNC_SIMPLE
+ GNM_FUNC_AUTO_FIRST
,
469 GNM_FUNC_IMPL_STATUS_COMPLETE
,
470 GNM_FUNC_TEST_STATUS_BASIC
473 help_product
, NULL
, gnumeric_product
,
474 NULL
, NULL
, GNM_FUNC_SIMPLE
,
475 GNM_FUNC_IMPL_STATUS_COMPLETE
,
476 GNM_FUNC_TEST_STATUS_BASIC
478 /* --- Gnumeric --- */
479 { "gnumeric_version", "",
480 help_gnumeric_version
, gnumeric_version
, NULL
,
481 NULL
, NULL
, GNM_FUNC_SIMPLE
,
482 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
,
483 GNM_FUNC_TEST_STATUS_EXHAUSTIVE
486 help_table
, NULL
, gnumeric_table
,
488 NULL
, GNM_FUNC_SIMPLE
+ GNM_FUNC_INTERNAL
,
489 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
,
490 GNM_FUNC_TEST_STATUS_EXHAUSTIVE
492 { "number_match", "s|s",
493 help_number_match
, gnumeric_number_match
, NULL
,
496 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
,
497 GNM_FUNC_TEST_STATUS_BASIC
},
500 help_if
, gnumeric_if
, NULL
,
502 GNM_FUNC_SIMPLE
+ GNM_FUNC_AUTO_SECOND
,
503 GNM_FUNC_IMPL_STATUS_COMPLETE
,
504 GNM_FUNC_TEST_STATUS_BASIC
},
508 gname
= N_("Mathematics");
509 math_group
= gnm_func_group_fetch (gname
, _(gname
));
510 gnm_func_add (math_group
, builtins
+ i
++, tdomain
);
511 gnm_func_add (math_group
, builtins
+ i
++, tdomain
);
513 gname
= N_("Gnumeric");
514 gnumeric_group
= gnm_func_group_fetch (gname
, _(gname
));
515 gnm_func_add (gnumeric_group
, builtins
+ i
++, tdomain
);
516 gnm_func_add (gnumeric_group
, builtins
+ i
++, tdomain
);
517 if (gnm_debug_flag ("testsuite"))
518 gnm_func_add (gnumeric_group
, builtins
+ i
, tdomain
);
522 logic_group
= gnm_func_group_fetch (gname
, _(gname
));
523 gnm_func_add (logic_group
, builtins
+ i
++, tdomain
);
525 gnm_expr_deriv_install_handler (gnm_func_lookup ("sum", NULL
),
527 GNM_EXPR_DERIV_NO_CHAIN
);
531 shutdown_cat (GnmFuncGroup
*group
)
533 GSList
*ptr
, *list
= g_slist_copy (group
->functions
);
534 for (ptr
= list
; ptr
; ptr
= ptr
->next
)
535 gnm_func_free (ptr
->data
);
540 func_builtin_shutdown (void)
542 shutdown_cat (math_group
);
543 shutdown_cat (gnumeric_group
);
544 shutdown_cat (logic_group
);