2 * collect.c: Helpers to collect ranges of data.
5 * Morten Welinder <terra@gnome.org>
6 * Jukka-Pekka Iivonen <iivonen@iki.fi>
9 #include <gnumeric-config.h>
14 #include <application.h>
17 #include <expr-impl.h>
18 #include <gnm-datetime.h>
22 #include <number-match.h>
23 #include <goffice/goffice.h>
27 /* ------------------------------------------------------------------------- */
38 } SingleFloatsCacheEntry
;
41 single_floats_cache_entry_free (SingleFloatsCacheEntry
*entry
)
43 value_release (entry
->value
);
44 value_release (entry
->error
);
50 single_floats_cache_entry_hash (const SingleFloatsCacheEntry
*entry
)
52 return value_hash (entry
->value
) ^ (guint
)entry
->flags
;
56 single_floats_cache_entry_equal (const SingleFloatsCacheEntry
*a
,
57 const SingleFloatsCacheEntry
*b
)
60 return (a
->flags
== b
->flags
&&
61 value_equal (a
->value
, b
->value
));
64 /* ------------------------------------------------------------------------- */
77 } PairsFloatsCacheEntry
;
80 pairs_floats_cache_entry_free (PairsFloatsCacheEntry
*entry
)
82 value_release (entry
->vx
);
83 value_release (entry
->vy
);
84 value_release (entry
->error
);
85 g_free (entry
->data_x
);
86 g_free (entry
->data_y
);
91 pairs_floats_cache_entry_hash (const PairsFloatsCacheEntry
*entry
)
93 /* FIXME: this does not consider the sheet, ie. the same pair of */
94 /* ranges on two different sheets yields the same hash value */
95 return value_hash (entry
->vx
) ^ (value_hash (entry
->vy
) << 1) ^ (guint
)entry
->flags
;
99 pairs_floats_cache_entry_equal (const PairsFloatsCacheEntry
*a
,
100 const PairsFloatsCacheEntry
*b
)
103 return (a
->flags
== b
->flags
&&
104 value_equal (a
->vx
, b
->vx
) &&
105 value_equal (a
->vy
, b
->vy
));
108 /* ------------------------------------------------------------------------- */
111 static gulong cache_handler
;
112 static GHashTable
*single_floats_cache
;
113 static GHashTable
*pairs_floats_cache
;
114 static size_t total_cache_size
;
122 g_signal_handler_disconnect (gnm_app_get_app (), cache_handler
);
125 g_hash_table_destroy (single_floats_cache
);
126 single_floats_cache
= NULL
;
127 g_hash_table_destroy (pairs_floats_cache
);
128 pairs_floats_cache
= NULL
;
130 total_cache_size
= 0;
140 g_signal_connect (gnm_app_get_app (), "recalc-clear-caches",
141 G_CALLBACK (clear_caches
), NULL
);
143 single_floats_cache
= g_hash_table_new_full
144 ((GHashFunc
)single_floats_cache_entry_hash
,
145 (GEqualFunc
)single_floats_cache_entry_equal
,
146 (GDestroyNotify
)single_floats_cache_entry_free
,
148 pairs_floats_cache
= g_hash_table_new_full
149 ((GHashFunc
)pairs_floats_cache_entry_hash
,
150 (GEqualFunc
)pairs_floats_cache_entry_equal
,
151 (GDestroyNotify
)pairs_floats_cache_entry_free
,
154 total_cache_size
= 0;
158 cb_prune (gpointer key
, gpointer value
, gpointer user
)
166 if (total_cache_size
> GNM_DEFAULT_ROWS
* 32) {
167 if (0) g_printerr ("Pruning collect cache from size %ld.\n",
168 (long)total_cache_size
);
170 total_cache_size
= 0;
171 g_hash_table_foreach_remove (single_floats_cache
,
174 g_hash_table_foreach_remove (pairs_floats_cache
,
180 static SingleFloatsCacheEntry
*
181 get_single_floats_cache_entry (GnmValue
const *value
, CollectFlags flags
)
183 SingleFloatsCacheEntry key
;
185 if (flags
& (COLLECT_INFO
| COLLECT_IGNORE_SUBTOTAL
))
190 key
.value
= (GnmValue
*)value
;
193 return g_hash_table_lookup (single_floats_cache
, &key
);
196 static PairsFloatsCacheEntry
*
197 get_pairs_floats_cache_entry (GnmValue
const *vx
, GnmValue
const *vy
,
200 PairsFloatsCacheEntry key
;
202 if (flags
& (COLLECT_INFO
| COLLECT_IGNORE_SUBTOTAL
))
207 key
.vx
= (GnmValue
*)vx
;
208 key
.vy
= (GnmValue
*)vy
;
211 return g_hash_table_lookup (pairs_floats_cache
, &key
);
214 static SingleFloatsCacheEntry
*
215 get_or_fake_cache_entry (GnmValue
const *key
, CollectFlags flags
,
216 GnmEvalPos
const *ep
)
218 SingleFloatsCacheEntry
*ce
;
220 ce
= get_single_floats_cache_entry (key
, flags
);
223 if (flags
& COLLECT_ORDER_IRRELEVANT
) {
224 ce
= get_single_floats_cache_entry (key
, flags
| COLLECT_SORT
);
229 if (flags
& COLLECT_SORT
) {
230 /* FIXME: Try unsorted. */
236 static PairsFloatsCacheEntry
*
237 get_or_fake_pairs_cache_entry (GnmValue
const *key_x
, GnmValue
const *key_y
,
239 GnmEvalPos
const *ep
)
241 PairsFloatsCacheEntry
*ce
;
243 ce
= get_pairs_floats_cache_entry (key_x
, key_y
, flags
);
246 /* FIXME: we should also try the pairs switched */
252 get_single_cache_key_from_value (GnmValue
const *r
, GnmEvalPos
const *ep
)
256 GnmRangeRef
const *rr
;
259 const int min_size
= 25;
261 rr
= value_get_rangeref (r
);
262 gnm_rangeref_normalize (rr
, ep
, &sr
.sheet
, &end_sheet
, &sr
.range
);
263 if (sr
.sheet
!= end_sheet
)
264 return NULL
; /* 3D */
266 h
= range_height (&sr
.range
);
267 w
= range_width (&sr
.range
);
268 if (h
< min_size
&& w
< min_size
&& h
* w
< min_size
)
271 key
= value_new_cellrange_r (sr
.sheet
, &sr
.range
);
277 get_single_cache_key (GnmExpr
const *e
, GnmEvalPos
const *ep
)
279 GnmValue
*r
= gnm_expr_get_range (e
);
282 GnmValue
*v
= get_single_cache_key_from_value (r
, ep
);
290 /* ------------------------------------------------------------------------- */
293 float_compare (const void *a_
, const void *b_
)
295 gnm_float
const *a
= a_
;
296 gnm_float
const *b
= b_
;
312 GODateConventions
const *date_conv
;
316 callback_function_collect (GnmEvalPos
const *ep
, GnmValue
const *value
,
320 collect_floats_t
*cl
= closure
;
321 gboolean ignore
= FALSE
;
323 switch (value
? value
->v_any
.type
: VALUE_EMPTY
) {
325 if (cl
->flags
& COLLECT_IGNORE_BLANKS
)
327 else if (cl
->flags
& COLLECT_ZERO_BLANKS
)
330 return value_new_error_VALUE (ep
);
334 if (cl
->flags
& COLLECT_IGNORE_BOOLS
)
336 else if (cl
->flags
& COLLECT_ZEROONE_BOOLS
)
337 x
= value_get_as_float (value
);
339 return value_new_error_VALUE (ep
);
342 case VALUE_CELLRANGE
:
344 /* Ranges and arrays are not singleton values treat as errors */
347 if (cl
->flags
& COLLECT_IGNORE_ERRORS
)
349 else if (cl
->flags
& COLLECT_ZERO_ERRORS
)
352 return value_new_error_VALUE (ep
);
356 x
= value_get_as_float (value
);
360 if (cl
->flags
& COLLECT_COERCE_STRINGS
) {
361 GnmValue
*vc
= format_match_number (value_peek_string (value
),
364 gboolean bad
= !vc
|| VALUE_IS_BOOLEAN (vc
);
366 x
= value_get_as_float (vc
);
372 return value_new_error_VALUE (ep
);
373 } else if (cl
->flags
& COLLECT_IGNORE_STRINGS
)
375 else if (cl
->flags
& COLLECT_ZERO_STRINGS
)
378 return value_new_error_VALUE (ep
);
382 g_warning ("Trouble in callback_function_collect. (%d)",
388 if (cl
->flags
& COLLECT_INFO
)
389 cl
->info
= g_slist_prepend (cl
->info
, GUINT_TO_POINTER (cl
->count
));
395 if (cl
->count
== cl
->alloc_count
) {
396 cl
->alloc_count
= cl
->alloc_count
* 2 + 20;
397 cl
->data
= g_renew (gnm_float
, cl
->data
, cl
->alloc_count
);
400 cl
->data
[cl
->count
++] = x
;
405 * collect_floats: (skip):
407 * exprlist: List of expressions to evaluate.
408 * cr: Current location (for resolving relative cells).
409 * flags: COLLECT_IGNORE_STRINGS: silently ignore strings.
410 * COLLECT_COERCE_STRINGS: coerce string into numbers
411 * COLLECT_ZERO_STRINGS: count strings as 0.
412 * (Alternative: return #VALUE!.)
413 * COLLECT_IGNORE_BOOLS: silently ignore bools.
414 * COLLECT_ZEROONE_BOOLS: count FALSE as 0, TRUE as 1.
415 * (Alternative: return #VALUE!.)
416 * COLLECT_IGNORE_SUBTOTAL : ignore expressions that include
417 * the function SUBTOTAL directly and ignore any content
419 * n: Output parameter for number of floats.
422 * NULL in case of strict and a blank.
423 * A copy of the error in the case of strict and an error.
424 * Non-NULL in case of success. Then n will be set.
426 * Evaluate a list of expressions and return the result as an array of
430 collect_floats (int argc
, GnmExprConstPtr
const *argv
,
431 GnmEvalPos
const *ep
, CollectFlags flags
,
432 int *n
, GnmValue
**error
, GSList
**info
,
436 CellIterFlags iter_flags
= CELL_ITER_ALL
;
437 GnmValue
*key
= NULL
;
438 CollectFlags keyflags
= flags
& ~COLLECT_ORDER_IRRELEVANT
;
446 g_return_val_if_fail (!(flags
& COLLECT_SORT
), NULL
);
447 flags
|= COLLECT_INFO
;
449 if (flags
& COLLECT_IGNORE_BLANKS
)
450 iter_flags
= CELL_ITER_IGNORE_BLANK
;
451 flags
&= ~COLLECT_INFO
;
454 /* ---------------------------------------- */
458 (flags
& (COLLECT_INFO
| COLLECT_IGNORE_SUBTOTAL
)) == 0) {
459 key
= get_single_cache_key (argv
[0], ep
);
462 SingleFloatsCacheEntry
*ce
=
463 get_or_fake_cache_entry (key
, keyflags
, ep
);
467 *error
= value_dup (ce
->error
);
475 return g_memdup (ce
->data
, *n
* sizeof (gnm_float
));
479 /* ---------------------------------------- */
481 if (flags
& COLLECT_IGNORE_SUBTOTAL
)
482 iter_flags
|= (CELL_ITER_IGNORE_SUBTOTAL
|
483 CELL_ITER_IGNORE_FILTERED
);
485 strict
= (flags
& (COLLECT_IGNORE_ERRORS
| COLLECT_ZERO_ERRORS
)) == 0;
492 cl
.date_conv
= sheet_date_conv (ep
->sheet
);
494 *error
= function_iterate_argument_values
495 (ep
, &callback_function_collect
, &cl
,
499 g_assert (VALUE_IS_ERROR (*error
));
503 g_slist_free (cl
.info
);
506 if (cl
.data
== NULL
) {
508 cl
.data
= g_new (gnm_float
, cl
.alloc_count
);
511 if (flags
& COLLECT_SORT
) {
512 qsort (cl
.data
, cl
.count
, sizeof (cl
.data
[0]),
522 SingleFloatsCacheEntry
*ce
= g_new (SingleFloatsCacheEntry
, 1);
523 SingleFloatsCacheEntry
*ce2
;
525 ce
->flags
= keyflags
;
527 ce
->error
= value_dup (*error
);
534 ce
->data
= g_memdup (cl
.data
, MAX (1, *n
) * sizeof (gnm_float
));
538 * We looked for the entry earlier and it was not there.
539 * However, sub-calculation might have added it so be careful
540 * to adjust sizes and replace the not-so-old entry.
543 ce2
= g_hash_table_lookup (single_floats_cache
, ce
);
545 total_cache_size
-= 1 + ce2
->n
;
547 g_hash_table_replace (single_floats_cache
, ce
, ce
);
548 total_cache_size
+= 1 + *n
;
553 /* ------------------------------------------------------------------------- */
554 /* Like collect_floats, but takes a value instead of an expression list.
555 Presumably most useful when the value is an array. */
558 collect_floats_value (GnmValue
const *val
, GnmEvalPos
const *ep
,
559 CollectFlags flags
, int *n
, GnmValue
**error
)
562 GnmExprConstPtr argv
[1] = { &expr_val
};
564 gnm_expr_constant_init (&expr_val
.constant
, val
);
565 return collect_floats (1, argv
, ep
, flags
, n
, error
, NULL
, NULL
);
568 /* ------------------------------------------------------------------------- */
570 * collect_floats_value_with_info:
573 * @flags: #CollectFlags
575 * @info: (element-type guint):
578 * Like collect_floats_value, but keeps info on missing values
582 collect_floats_value_with_info (GnmValue
const *val
, GnmEvalPos
const *ep
,
583 CollectFlags flags
, int *n
, GSList
**info
,
587 GnmExprConstPtr argv
[1] = { &expr_val
};
590 gnm_expr_constant_init (&expr_val
.constant
, val
);
591 res
= collect_floats (1, argv
, ep
, flags
, n
, error
, info
, NULL
);
594 *info
= g_slist_reverse (*info
);
600 /* ------------------------------------------------------------------------- */
603 * float_range_function:
604 * @argc: number of arguments
605 * @argv: (in) (array length=argc): function arguments
606 * @ei: #GnmFuncEvalInfo describing evaluation context
607 * @func: (scope call): implementation function
608 * @flags: #CollectFlags flags describing the collection and interpretation
609 * of values from @argv.
610 * @func_error: A #GnmStdError to use to @func indicates an error.
612 * This implements a Gnumeric sheet function that operates on a list of
613 * numbers. This function collects the arguments and uses @func to do
614 * the actual computation.
616 * Returns: (transfer full): Function result or error value.
619 float_range_function (int argc
, GnmExprConstPtr
const *argv
,
621 float_range_function_t func
,
623 GnmStdError func_error
)
625 GnmValue
*error
= NULL
;
626 gnm_float
*vals
, res
;
630 vals
= collect_floats (argc
, argv
, ei
->pos
, flags
, &n
, &error
,
635 err
= func (vals
, n
, &res
);
636 if (!constp
) g_free (vals
);
639 return value_new_error_std (ei
->pos
, func_error
);
641 return value_new_float (res
);
644 /* ------------------------------------------------------------------------- */
647 * gnm_slist_sort_merge:
648 * @list_1: (element-type guint) (transfer container): a sorted list of
649 * unsigned integers with no duplicates.
650 * @list_2: (element-type guint) (transfer container): another one
652 * gnm_slist_sort_merge merges two lists of unsigned integers.
654 * Returns: (element-type guint) (transfer container): the mergedlist.
657 gnm_slist_sort_merge (GSList
*l1
,
665 if (GPOINTER_TO_UINT (l1
->data
) <= GPOINTER_TO_UINT (l2
->data
)) {
666 if (GPOINTER_TO_UINT (l1
->data
) == GPOINTER_TO_UINT (l2
->data
)) {
667 /* remove duplicates */
680 l
->next
= l1
? l1
: l2
;
688 * @data: (inout) (array length=n): Array
689 * @n: (inout): Number of elements in @data.
690 * @missing: (element-type guint): indices of elements to remove in increasing
693 * This removes the data elements from @data whose indices are given by
694 * @missing. @n is the number of elements and it updated upon return.
697 gnm_strip_missing (gnm_float
*data
, int *n
, GSList
*missing
)
704 for (src
= dst
= 0; (int)dst
< *n
; src
++) {
705 if (missing
&& src
== GPOINTER_TO_UINT (missing
->data
)) {
706 missing
= missing
->next
;
709 data
[dst
] = data
[src
];
715 static PairsFloatsCacheEntry
*
716 collect_float_pairs_ce (GnmValue
const *vx
, GnmValue
const *vy
,
717 GnmEvalPos
const *ep
, CollectFlags flags
)
719 PairsFloatsCacheEntry
*ce
= g_new0 (PairsFloatsCacheEntry
, 1);
720 GSList
*missing0
= NULL
, *missing1
= NULL
;
725 ce
->data_x
= collect_floats_value_with_info (vx
, ep
, flags
,
726 &n0
, &missing0
, &ce
->error
);
730 ce
->data_y
= collect_floats_value_with_info (vy
, ep
, flags
,
731 &n1
, &missing1
, &ce
->error
);
741 if (missing0
|| missing1
) {
742 missing0
= gnm_slist_sort_merge (missing0
, missing1
);
744 gnm_strip_missing (ce
->data_x
, &n0
, missing0
);
745 gnm_strip_missing (ce
->data_y
, &n1
, missing0
);
757 g_slist_free (missing0
);
758 g_slist_free (missing1
);
764 * collect_float_pairs: (skip)
765 * @v0: value describing first data range
766 * @v1: value describing second data range
767 * @ep: evaluation position
768 * @flags: flags describing how to handle value types
769 * @xs0: (out) (array length=n): return location for first data vector
770 * @xs1: (out) (array length=n): return location for second data vector
771 * @n: (out): return location for number of data points
772 * @constp: (out) (optional): Return location for a flag describing who own
773 * the vectors returned in @xs0 and @xs1. If present and %TRUE, the
774 * resulting data vectors in @xs0 and @xs1 are not owned by the caller.
775 * If not-present or %FALSE, the callers owns and must free the result.
777 * If @n is not positive upon return, no data has been allocated.
778 * If @n is negative upon return, the two ranges had different sizes.
780 * Note: introspection cannot handle this functions parameter mix.
782 * Returns: (transfer full) (nullable): Error value.
785 collect_float_pairs (GnmValue
const *vx
, GnmValue
const *vy
,
786 GnmEvalPos
const *ep
, CollectFlags flags
,
787 gnm_float
**xs0
, gnm_float
**xs1
, int *n
,
790 GnmValue
*key_x
= NULL
;
791 GnmValue
*key_y
= NULL
;
792 PairsFloatsCacheEntry
*ce
= NULL
;
793 gboolean use_cache
, free_keys
= TRUE
;
795 if (VALUE_IS_CELLRANGE (vx
))
796 key_x
= get_single_cache_key_from_value (vx
, ep
);
797 if (VALUE_IS_CELLRANGE (vy
))
798 key_y
= get_single_cache_key_from_value (vy
, ep
);
800 if ((use_cache
= (key_x
&& key_y
)))
801 ce
= get_or_fake_pairs_cache_entry (key_x
, key_y
, flags
, ep
);
804 ce
= collect_float_pairs_ce (vx
, vy
, ep
, flags
);
806 PairsFloatsCacheEntry
*ce2
;
812 * We looked for the entry earlier and it was not there.
813 * However, sub-calculation might have added it so be careful
814 * to adjust sizes and replace the not-so-old entry.
817 ce2
= g_hash_table_lookup (pairs_floats_cache
, ce
);
819 total_cache_size
-= 1 + ce2
->n
;
821 g_hash_table_replace (pairs_floats_cache
, ce
, ce
);
822 total_cache_size
+= 1 + ce
->n
;
827 value_release (key_x
);
828 value_release (key_y
);
832 return value_new_error_VALUE (ep
);
836 return value_dup (ce
->error
);
838 GnmValue
*ret
= ce
->error
;
840 pairs_floats_cache_entry_free (ce
);
847 pairs_floats_cache_entry_free (ce
);
860 *xs0
= g_memdup (ce
->data_x
, *n
* sizeof (gnm_float
));
861 *xs1
= g_memdup (ce
->data_y
, *n
* sizeof (gnm_float
));
870 pairs_floats_cache_entry_free (ce
);
877 * float_range_function2d:
879 * @val1: Second range
880 * @ei: #GnmFuncEvalInfo describing evaluation context
881 * @func: (scope call): implementation function
882 * @flags: #CollectFlags flags describing the collection and interpretation
883 * of values from @val0 and @val1.
884 * @func_error: A #GnmStdError to use to @func indicates an error.
885 * @data: user data for @func
887 * This implements a Gnumeric sheet function that operates on a matched
888 * pair of ranges. This function collects the arguments and uses @func to do
889 * the actual computation.
891 * Returns: (transfer full): Function result or error value.
894 float_range_function2d (GnmValue
const *val0
, GnmValue
const *val1
,
896 float_range_function2d_t func
,
898 GnmStdError func_error
,
901 gnm_float
*vals0
, *vals1
;
905 gboolean constp
= FALSE
;
907 res
= collect_float_pairs (val0
, val1
, ei
->pos
, flags
,
908 &vals0
, &vals1
, &n
, &constp
);
913 return value_new_error_std (ei
->pos
, func_error
);
915 if (func (vals0
, vals1
, n
, &fres
, data
))
916 res
= value_new_error_std (ei
->pos
, func_error
);
918 res
= value_new_float (fres
);
928 * float_range_function2:
930 * @val1: Second range
931 * @ei: #GnmFuncEvalInfo describing evaluation context
932 * @func: (scope call): implementation function
933 * @flags: #CollectFlags flags describing the collection and interpretation
934 * of values from @val0 and @val1.
935 * @func_error: A #GnmStdError to use to @func indicates an error.
937 * This implements a Gnumeric sheet function that operates on a matched
938 * pair of ranges. This function collects the arguments and uses @func to do
939 * the actual computation.
941 * Returns: (transfer full): Function result or error value.
944 float_range_function2 (GnmValue
const *val0
, GnmValue
const *val1
,
946 float_range_function2_t func
,
948 GnmStdError func_error
)
950 return float_range_function2d (val0
, val1
, ei
,
951 (float_range_function2d_t
)func
,
957 /* ------------------------------------------------------------------------- */
958 /* ------------------------------------------------------------------------- */
966 callback_function_collect_strings (GnmEvalPos
const *ep
, GnmValue
const *value
,
970 collect_strings_t
*cl
= closure
;
972 if (VALUE_IS_EMPTY (value
)) {
973 if (cl
->flags
& COLLECT_IGNORE_BLANKS
)
976 text
= g_strdup ("");
978 text
= value_get_as_string (value
);
981 g_ptr_array_add (cl
->data
, text
);
987 collect_strings_free (GPtrArray
*data
)
989 g_ptr_array_foreach (data
, (GFunc
)g_free
, NULL
);
990 g_ptr_array_free (data
, TRUE
);
995 * @argc: number of arguments
996 * @argv: (in) (array length=argc): function arguments
997 * @ep: Evaluation position
998 * @flags: #CollectFlags flags describing the collection and interpretation
999 * of values from @argv.
1000 * @error: (out): Error return value
1002 * Evaluate a list of expressions and return the result as a #GPtrArray of
1005 * Returns: (transfer full) (nullable) (element-type utf8): array of strings.
1008 collect_strings (int argc
, GnmExprConstPtr
const *argv
,
1009 GnmEvalPos
const *ep
, CollectFlags flags
,
1012 collect_strings_t cl
;
1013 CellIterFlags iter_flags
= CELL_ITER_ALL
;
1016 /* We don't handle these flags */
1017 g_return_val_if_fail (!(flags
& COLLECT_ZERO_ERRORS
), NULL
);
1018 g_return_val_if_fail (!(flags
& COLLECT_ZERO_STRINGS
), NULL
);
1019 g_return_val_if_fail (!(flags
& COLLECT_ZEROONE_BOOLS
), NULL
);
1020 g_return_val_if_fail (!(flags
& COLLECT_ZERO_BLANKS
), NULL
);
1022 if (flags
& COLLECT_IGNORE_BLANKS
)
1023 iter_flags
= CELL_ITER_IGNORE_BLANK
;
1025 strict
= (flags
& (COLLECT_IGNORE_ERRORS
| COLLECT_ZERO_ERRORS
)) == 0;
1027 cl
.data
= g_ptr_array_new ();
1030 *error
= function_iterate_argument_values
1031 (ep
, &callback_function_collect_strings
, &cl
,
1033 strict
, iter_flags
);
1035 g_assert (VALUE_IS_ERROR (*error
));
1036 collect_strings_free (cl
.data
);
1044 * string_range_function:
1045 * @argc: number of arguments
1046 * @argv: (in) (array length=argc): function arguments
1047 * @ei: #GnmFuncEvalInfo describing evaluation context
1048 * @func: (scope call): implementation function
1049 * @flags: #CollectFlags flags describing the collection and interpretation
1050 * of values from @argv.
1051 * @func_error: A #GnmStdError to use to @func indicates an error.
1053 * This implements a Gnumeric sheet function that operates on a list of
1054 * strings. This function collects the arguments and uses @func to do
1055 * the actual computation.
1057 * Returns: (transfer full): Function result or error value.
1060 string_range_function (int argc
, GnmExprConstPtr
const *argv
,
1061 GnmFuncEvalInfo
*ei
,
1062 string_range_function_t func
,
1065 GnmStdError func_error
)
1067 GnmValue
*error
= NULL
;
1072 vals
= collect_strings (argc
, argv
, ei
->pos
, flags
, &error
);
1076 err
= func (vals
, &res
, user
);
1078 collect_strings_free (vals
);
1082 return value_new_error_std (ei
->pos
, func_error
);
1084 return value_new_string_nocopy (res
);