1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * collect.c: Helpers to collect ranges of data.
6 * Morten Welinder <terra@gnome.org>
7 * Jukka-Pekka Iivonen <iivonen@iki.fi>
10 #include <gnumeric-config.h>
15 #include "application.h"
18 #include "expr-impl.h"
19 #include "gnm-datetime.h"
23 #include "number-match.h"
24 #include <goffice/goffice.h>
28 /* ------------------------------------------------------------------------- */
39 } SingleFloatsCacheEntry
;
42 single_floats_cache_entry_free (SingleFloatsCacheEntry
*entry
)
44 value_release (entry
->value
);
45 value_release (entry
->error
);
51 single_floats_cache_entry_hash (const SingleFloatsCacheEntry
*entry
)
53 return value_hash (entry
->value
) ^ (guint
)entry
->flags
;
57 single_floats_cache_entry_equal (const SingleFloatsCacheEntry
*a
,
58 const SingleFloatsCacheEntry
*b
)
61 return (a
->flags
== b
->flags
&&
62 value_equal (a
->value
, b
->value
));
65 /* ------------------------------------------------------------------------- */
78 } PairsFloatsCacheEntry
;
81 pairs_floats_cache_entry_free (PairsFloatsCacheEntry
*entry
)
83 value_release (entry
->vx
);
84 value_release (entry
->vy
);
85 value_release (entry
->error
);
86 g_free (entry
->data_x
);
87 g_free (entry
->data_y
);
92 pairs_floats_cache_entry_hash (const PairsFloatsCacheEntry
*entry
)
94 /* FIXME: this does not consider the sheet, ie. the same pair of */
95 /* ranges on two different sheets yields the same hash value */
96 return value_hash (entry
->vx
) ^ (value_hash (entry
->vy
) << 1) ^ (guint
)entry
->flags
;
100 pairs_floats_cache_entry_equal (const PairsFloatsCacheEntry
*a
,
101 const PairsFloatsCacheEntry
*b
)
104 return (a
->flags
== b
->flags
&&
105 value_equal (a
->vx
, b
->vx
) &&
106 value_equal (a
->vy
, b
->vy
));
109 /* ------------------------------------------------------------------------- */
112 static gulong cache_handler
;
113 static GHashTable
*single_floats_cache
;
114 static GHashTable
*pairs_floats_cache
;
115 static size_t total_cache_size
;
123 g_signal_handler_disconnect (gnm_app_get_app (), cache_handler
);
126 g_hash_table_destroy (single_floats_cache
);
127 single_floats_cache
= NULL
;
128 g_hash_table_destroy (pairs_floats_cache
);
129 pairs_floats_cache
= NULL
;
131 total_cache_size
= 0;
141 g_signal_connect (gnm_app_get_app (), "recalc-clear-caches",
142 G_CALLBACK (clear_caches
), NULL
);
144 single_floats_cache
= g_hash_table_new_full
145 ((GHashFunc
)single_floats_cache_entry_hash
,
146 (GEqualFunc
)single_floats_cache_entry_equal
,
147 (GDestroyNotify
)single_floats_cache_entry_free
,
149 pairs_floats_cache
= g_hash_table_new_full
150 ((GHashFunc
)pairs_floats_cache_entry_hash
,
151 (GEqualFunc
)pairs_floats_cache_entry_equal
,
152 (GDestroyNotify
)pairs_floats_cache_entry_free
,
155 total_cache_size
= 0;
159 cb_prune (gpointer key
, gpointer value
, gpointer user
)
167 if (total_cache_size
> GNM_DEFAULT_ROWS
* 32) {
168 if (0) g_printerr ("Pruning collect cache from size %ld.\n",
169 (long)total_cache_size
);
171 total_cache_size
= 0;
172 g_hash_table_foreach_remove (single_floats_cache
,
175 g_hash_table_foreach_remove (pairs_floats_cache
,
181 static SingleFloatsCacheEntry
*
182 get_single_floats_cache_entry (GnmValue
const *value
, CollectFlags flags
)
184 SingleFloatsCacheEntry key
;
186 if (flags
& (COLLECT_INFO
| COLLECT_IGNORE_SUBTOTAL
))
191 key
.value
= (GnmValue
*)value
;
194 return g_hash_table_lookup (single_floats_cache
, &key
);
197 static PairsFloatsCacheEntry
*
198 get_pairs_floats_cache_entry (GnmValue
const *vx
, GnmValue
const *vy
,
201 PairsFloatsCacheEntry key
;
203 if (flags
& (COLLECT_INFO
| COLLECT_IGNORE_SUBTOTAL
))
208 key
.vx
= (GnmValue
*)vx
;
209 key
.vy
= (GnmValue
*)vy
;
212 return g_hash_table_lookup (pairs_floats_cache
, &key
);
215 static SingleFloatsCacheEntry
*
216 get_or_fake_cache_entry (GnmValue
const *key
, CollectFlags flags
,
217 GnmEvalPos
const *ep
)
219 SingleFloatsCacheEntry
*ce
;
221 ce
= get_single_floats_cache_entry (key
, flags
);
224 if (flags
& COLLECT_ORDER_IRRELEVANT
) {
225 ce
= get_single_floats_cache_entry (key
, flags
| COLLECT_SORT
);
230 if (flags
& COLLECT_SORT
) {
231 /* FIXME: Try unsorted. */
237 static PairsFloatsCacheEntry
*
238 get_or_fake_pairs_cache_entry (GnmValue
const *key_x
, GnmValue
const *key_y
,
240 GnmEvalPos
const *ep
)
242 PairsFloatsCacheEntry
*ce
;
244 ce
= get_pairs_floats_cache_entry (key_x
, key_y
, flags
);
247 /* FIXME: we should also try the pairs switched */
253 get_single_cache_key_from_value (GnmValue
const *r
, GnmEvalPos
const *ep
)
257 GnmRangeRef
const *rr
;
260 const int min_size
= 25;
262 rr
= value_get_rangeref (r
);
263 gnm_rangeref_normalize (rr
, ep
, &sr
.sheet
, &end_sheet
, &sr
.range
);
264 if (sr
.sheet
!= end_sheet
)
265 return NULL
; /* 3D */
267 h
= range_height (&sr
.range
);
268 w
= range_width (&sr
.range
);
269 if (h
< min_size
&& w
< min_size
&& h
* w
< min_size
)
272 key
= value_new_cellrange_r (sr
.sheet
, &sr
.range
);
278 get_single_cache_key (GnmExpr
const *e
, GnmEvalPos
const *ep
)
280 GnmValue
*r
= gnm_expr_get_range (e
);
283 GnmValue
*v
= get_single_cache_key_from_value (r
, ep
);
291 /* ------------------------------------------------------------------------- */
294 float_compare (const void *a_
, const void *b_
)
296 gnm_float
const *a
= a_
;
297 gnm_float
const *b
= b_
;
313 GODateConventions
const *date_conv
;
317 callback_function_collect (GnmEvalPos
const *ep
, GnmValue
const *value
,
321 collect_floats_t
*cl
= closure
;
322 gboolean ignore
= FALSE
;
324 switch (value
? value
->v_any
.type
: VALUE_EMPTY
) {
326 if (cl
->flags
& COLLECT_IGNORE_BLANKS
)
328 else if (cl
->flags
& COLLECT_ZERO_BLANKS
)
331 return value_new_error_VALUE (ep
);
335 if (cl
->flags
& COLLECT_IGNORE_BOOLS
)
337 else if (cl
->flags
& COLLECT_ZEROONE_BOOLS
)
338 x
= value_get_as_float (value
);
340 return value_new_error_VALUE (ep
);
343 case VALUE_CELLRANGE
:
345 /* Ranges and arrays are not singleton values treat as errors */
348 if (cl
->flags
& COLLECT_IGNORE_ERRORS
)
350 else if (cl
->flags
& COLLECT_ZERO_ERRORS
)
353 return value_new_error_VALUE (ep
);
357 x
= value_get_as_float (value
);
361 if (cl
->flags
& COLLECT_COERCE_STRINGS
) {
362 GnmValue
*vc
= format_match_number (value_peek_string (value
),
365 gboolean bad
= !vc
|| VALUE_IS_BOOLEAN (vc
);
367 x
= value_get_as_float (vc
);
373 return value_new_error_VALUE (ep
);
374 } else if (cl
->flags
& COLLECT_IGNORE_STRINGS
)
376 else if (cl
->flags
& COLLECT_ZERO_STRINGS
)
379 return value_new_error_VALUE (ep
);
383 g_warning ("Trouble in callback_function_collect. (%d)",
389 if (cl
->flags
& COLLECT_INFO
)
390 cl
->info
= g_slist_prepend (cl
->info
, GUINT_TO_POINTER (cl
->count
));
396 if (cl
->count
== cl
->alloc_count
) {
397 cl
->alloc_count
= cl
->alloc_count
* 2 + 20;
398 cl
->data
= g_renew (gnm_float
, cl
->data
, cl
->alloc_count
);
401 cl
->data
[cl
->count
++] = x
;
406 * collect_floats: (skip):
408 * exprlist: List of expressions to evaluate.
409 * cr: Current location (for resolving relative cells).
410 * flags: COLLECT_IGNORE_STRINGS: silently ignore strings.
411 * COLLECT_COERCE_STRINGS: coerce string into numbers
412 * COLLECT_ZERO_STRINGS: count strings as 0.
413 * (Alternative: return #VALUE!.)
414 * COLLECT_IGNORE_BOOLS: silently ignore bools.
415 * COLLECT_ZEROONE_BOOLS: count FALSE as 0, TRUE as 1.
416 * (Alternative: return #VALUE!.)
417 * COLLECT_IGNORE_SUBTOTAL : ignore expressions that include
418 * the function SUBTOTAL directly and ignore any content
420 * n: Output parameter for number of floats.
423 * NULL in case of strict and a blank.
424 * A copy of the error in the case of strict and an error.
425 * Non-NULL in case of success. Then n will be set.
427 * Evaluate a list of expressions and return the result as an array of
431 collect_floats (int argc
, GnmExprConstPtr
const *argv
,
432 GnmEvalPos
const *ep
, CollectFlags flags
,
433 int *n
, GnmValue
**error
, GSList
**info
,
437 CellIterFlags iter_flags
= CELL_ITER_ALL
;
438 GnmValue
*key
= NULL
;
439 CollectFlags keyflags
= flags
& ~COLLECT_ORDER_IRRELEVANT
;
447 g_return_val_if_fail (!(flags
& COLLECT_SORT
), NULL
);
448 flags
|= COLLECT_INFO
;
450 if (flags
& COLLECT_IGNORE_BLANKS
)
451 iter_flags
= CELL_ITER_IGNORE_BLANK
;
452 flags
&= ~COLLECT_INFO
;
455 /* ---------------------------------------- */
459 (flags
& (COLLECT_INFO
| COLLECT_IGNORE_SUBTOTAL
)) == 0) {
460 key
= get_single_cache_key (argv
[0], ep
);
463 SingleFloatsCacheEntry
*ce
=
464 get_or_fake_cache_entry (key
, keyflags
, ep
);
468 *error
= value_dup (ce
->error
);
476 return g_memdup (ce
->data
, *n
* sizeof (gnm_float
));
480 /* ---------------------------------------- */
482 if (flags
& COLLECT_IGNORE_SUBTOTAL
)
483 iter_flags
|= (CELL_ITER_IGNORE_SUBTOTAL
|
484 CELL_ITER_IGNORE_FILTERED
);
486 strict
= (flags
& (COLLECT_IGNORE_ERRORS
| COLLECT_ZERO_ERRORS
)) == 0;
493 cl
.date_conv
= sheet_date_conv (ep
->sheet
);
495 *error
= function_iterate_argument_values
496 (ep
, &callback_function_collect
, &cl
,
500 g_assert (VALUE_IS_ERROR (*error
));
504 g_slist_free (cl
.info
);
507 if (cl
.data
== NULL
) {
509 cl
.data
= g_new (gnm_float
, cl
.alloc_count
);
512 if (flags
& COLLECT_SORT
) {
513 qsort (cl
.data
, cl
.count
, sizeof (cl
.data
[0]),
523 SingleFloatsCacheEntry
*ce
= g_new (SingleFloatsCacheEntry
, 1);
524 SingleFloatsCacheEntry
*ce2
;
526 ce
->flags
= keyflags
;
528 ce
->error
= value_dup (*error
);
535 ce
->data
= g_memdup (cl
.data
, MAX (1, *n
) * sizeof (gnm_float
));
539 * We looked for the entry earlier and it was not there.
540 * However, sub-calculation might have added it so be careful
541 * to adjust sizes and replace the not-so-old entry.
544 ce2
= g_hash_table_lookup (single_floats_cache
, ce
);
546 total_cache_size
-= 1 + ce2
->n
;
548 g_hash_table_replace (single_floats_cache
, ce
, ce
);
549 total_cache_size
+= 1 + *n
;
554 /* ------------------------------------------------------------------------- */
555 /* Like collect_floats, but takes a value instead of an expression list.
556 Presumably most useful when the value is an array. */
559 collect_floats_value (GnmValue
const *val
, GnmEvalPos
const *ep
,
560 CollectFlags flags
, int *n
, GnmValue
**error
)
563 GnmExprConstPtr argv
[1] = { &expr_val
};
565 gnm_expr_constant_init (&expr_val
.constant
, val
);
566 return collect_floats (1, argv
, ep
, flags
, n
, error
, NULL
, NULL
);
569 /* ------------------------------------------------------------------------- */
571 * collect_floats_value_with_info:
574 * @flags: #CollectFlags
576 * @info: (element-type guint):
579 * Like collect_floats_value, but keeps info on missing values
583 collect_floats_value_with_info (GnmValue
const *val
, GnmEvalPos
const *ep
,
584 CollectFlags flags
, int *n
, GSList
**info
,
588 GnmExprConstPtr argv
[1] = { &expr_val
};
591 gnm_expr_constant_init (&expr_val
.constant
, val
);
592 res
= collect_floats (1, argv
, ep
, flags
, n
, error
, info
, NULL
);
595 *info
= g_slist_reverse (*info
);
601 /* ------------------------------------------------------------------------- */
604 * float_range_function:
605 * @argc: number of arguments
606 * @argv: (in) (array length=argc): function arguments
607 * @ei: #GnmFuncEvalInfo describing evaluation context
608 * @func: (scope call): implementation function
609 * @flags: #CollectFlags flags describing the collection and interpretation
610 * of values from @argv.
611 * @func_error: A #GnmStdError to use to @func indicates an error.
613 * This implements a Gnumeric sheet function that operates on a list of
614 * numbers. This function collects the arguments and uses @func to do
615 * the actual computation.
617 * Returns: (transfer full): Function result or error value.
620 float_range_function (int argc
, GnmExprConstPtr
const *argv
,
622 float_range_function_t func
,
624 GnmStdError func_error
)
626 GnmValue
*error
= NULL
;
627 gnm_float
*vals
, res
;
631 vals
= collect_floats (argc
, argv
, ei
->pos
, flags
, &n
, &error
,
636 err
= func (vals
, n
, &res
);
637 if (!constp
) g_free (vals
);
640 return value_new_error_std (ei
->pos
, func_error
);
642 return value_new_float (res
);
645 /* ------------------------------------------------------------------------- */
648 * gnm_slist_sort_merge:
649 * @list_1: (element-type guint) (transfer container): a sorted list of
650 * unsigned integers with no duplicates.
651 * @list_2: (element-type guint) (transfer container): another one
653 * gnm_slist_sort_merge merges two lists of unsigned integers.
655 * Returns: (element-type guint) (transfer container): the mergedlist.
658 gnm_slist_sort_merge (GSList
*l1
,
666 if (GPOINTER_TO_UINT (l1
->data
) <= GPOINTER_TO_UINT (l2
->data
)) {
667 if (GPOINTER_TO_UINT (l1
->data
) == GPOINTER_TO_UINT (l2
->data
)) {
668 /* remove duplicates */
681 l
->next
= l1
? l1
: l2
;
689 * @data: (inout) (array length=n): Array
690 * @n: (inout): Number of elements in @data.
691 * @missing: (element-type guint): indices of elements to remove in increasing
694 * This removes the data elements from @data whose indices are given by
695 * @missing. @n is the number of elements and it updated upon return.
698 gnm_strip_missing (gnm_float
*data
, int *n
, GSList
*missing
)
705 for (src
= dst
= 0; (int)dst
< *n
; src
++) {
706 if (missing
&& src
== GPOINTER_TO_UINT (missing
->data
)) {
707 missing
= missing
->next
;
710 data
[dst
] = data
[src
];
716 static PairsFloatsCacheEntry
*
717 collect_float_pairs_ce (GnmValue
const *vx
, GnmValue
const *vy
,
718 GnmEvalPos
const *ep
, CollectFlags flags
)
720 PairsFloatsCacheEntry
*ce
= g_new0 (PairsFloatsCacheEntry
, 1);
721 GSList
*missing0
= NULL
, *missing1
= NULL
;
726 ce
->data_x
= collect_floats_value_with_info (vx
, ep
, flags
,
727 &n0
, &missing0
, &ce
->error
);
731 ce
->data_y
= collect_floats_value_with_info (vy
, ep
, flags
,
732 &n1
, &missing1
, &ce
->error
);
742 if (missing0
|| missing1
) {
743 missing0
= gnm_slist_sort_merge (missing0
, missing1
);
745 gnm_strip_missing (ce
->data_x
, &n0
, missing0
);
746 gnm_strip_missing (ce
->data_y
, &n1
, missing0
);
758 g_slist_free (missing0
);
759 g_slist_free (missing1
);
765 * collect_float_pairs: (skip)
766 * @v0: value describing first data range
767 * @v1: value describing second data range
768 * @ep: evaluation position
769 * @flags: flags describing how to handle value types
770 * @xs0: (out) (array length=n): return location for first data vector
771 * @xs1: (out) (array length=n): return location for second data vector
772 * @n: (out): return location for number of data points
773 * @constp: (out) (optional): Return location for a flag describing who own
774 * the vectors returned in @xs0 and @xs1. If present and %TRUE, the
775 * resulting data vectors in @xs0 and @xs1 are not owned by the caller.
776 * If not-present or %FALSE, the callers owns and must free the result.
778 * If @n is not positive upon return, no data has been allocated.
779 * If @n is negative upon return, the two ranges had different sizes.
781 * Note: introspection cannot handle this functions parameter mix.
783 * Returns: (transfer full) (nullable): Error value.
786 collect_float_pairs (GnmValue
const *vx
, GnmValue
const *vy
,
787 GnmEvalPos
const *ep
, CollectFlags flags
,
788 gnm_float
**xs0
, gnm_float
**xs1
, int *n
,
791 GnmValue
*key_x
= NULL
;
792 GnmValue
*key_y
= NULL
;
793 PairsFloatsCacheEntry
*ce
= NULL
;
794 gboolean use_cache
, free_keys
= TRUE
;
796 if (VALUE_IS_CELLRANGE (vx
))
797 key_x
= get_single_cache_key_from_value (vx
, ep
);
798 if (VALUE_IS_CELLRANGE (vy
))
799 key_y
= get_single_cache_key_from_value (vy
, ep
);
801 if ((use_cache
= (key_x
&& key_y
)))
802 ce
= get_or_fake_pairs_cache_entry (key_x
, key_y
, flags
, ep
);
805 ce
= collect_float_pairs_ce (vx
, vy
, ep
, flags
);
807 PairsFloatsCacheEntry
*ce2
;
813 * We looked for the entry earlier and it was not there.
814 * However, sub-calculation might have added it so be careful
815 * to adjust sizes and replace the not-so-old entry.
818 ce2
= g_hash_table_lookup (pairs_floats_cache
, ce
);
820 total_cache_size
-= 1 + ce2
->n
;
822 g_hash_table_replace (pairs_floats_cache
, ce
, ce
);
823 total_cache_size
+= 1 + ce
->n
;
828 value_release (key_x
);
829 value_release (key_y
);
833 return value_new_error_VALUE (ep
);
837 return value_dup (ce
->error
);
839 GnmValue
*ret
= ce
->error
;
841 pairs_floats_cache_entry_free (ce
);
848 pairs_floats_cache_entry_free (ce
);
861 *xs0
= g_memdup (ce
->data_x
, *n
* sizeof (gnm_float
));
862 *xs1
= g_memdup (ce
->data_y
, *n
* sizeof (gnm_float
));
871 pairs_floats_cache_entry_free (ce
);
878 * float_range_function2d:
880 * @val1: Second range
881 * @ei: #GnmFuncEvalInfo describing evaluation context
882 * @func: (scope call): implementation function
883 * @flags: #CollectFlags flags describing the collection and interpretation
884 * of values from @val0 and @val1.
885 * @func_error: A #GnmStdError to use to @func indicates an error.
886 * @data: user data for @func
888 * This implements a Gnumeric sheet function that operates on a matched
889 * pair of ranges. This function collects the arguments and uses @func to do
890 * the actual computation.
892 * Returns: (transfer full): Function result or error value.
895 float_range_function2d (GnmValue
const *val0
, GnmValue
const *val1
,
897 float_range_function2d_t func
,
899 GnmStdError func_error
,
902 gnm_float
*vals0
, *vals1
;
906 gboolean constp
= FALSE
;
908 res
= collect_float_pairs (val0
, val1
, ei
->pos
, flags
,
909 &vals0
, &vals1
, &n
, &constp
);
914 return value_new_error_std (ei
->pos
, func_error
);
916 if (func (vals0
, vals1
, n
, &fres
, data
))
917 res
= value_new_error_std (ei
->pos
, func_error
);
919 res
= value_new_float (fres
);
929 * float_range_function2:
931 * @val1: Second range
932 * @ei: #GnmFuncEvalInfo describing evaluation context
933 * @func: (scope call): implementation function
934 * @flags: #CollectFlags flags describing the collection and interpretation
935 * of values from @val0 and @val1.
936 * @func_error: A #GnmStdError to use to @func indicates an error.
938 * This implements a Gnumeric sheet function that operates on a matched
939 * pair of ranges. This function collects the arguments and uses @func to do
940 * the actual computation.
942 * Returns: (transfer full): Function result or error value.
945 float_range_function2 (GnmValue
const *val0
, GnmValue
const *val1
,
947 float_range_function2_t func
,
949 GnmStdError func_error
)
951 return float_range_function2d (val0
, val1
, ei
,
952 (float_range_function2d_t
)func
,
958 /* ------------------------------------------------------------------------- */
959 /* ------------------------------------------------------------------------- */
967 callback_function_collect_strings (GnmEvalPos
const *ep
, GnmValue
const *value
,
971 collect_strings_t
*cl
= closure
;
973 if (VALUE_IS_EMPTY (value
)) {
974 if (cl
->flags
& COLLECT_IGNORE_BLANKS
)
977 text
= g_strdup ("");
979 text
= value_get_as_string (value
);
982 g_ptr_array_add (cl
->data
, text
);
988 collect_strings_free (GPtrArray
*data
)
990 g_ptr_array_foreach (data
, (GFunc
)g_free
, NULL
);
991 g_ptr_array_free (data
, TRUE
);
996 * @argc: number of arguments
997 * @argv: (in) (array length=argc): function arguments
998 * @ep: Evaluation position
999 * @flags: #CollectFlags flags describing the collection and interpretation
1000 * of values from @argv.
1001 * @error: (out): Error return value
1003 * Evaluate a list of expressions and return the result as a #GPtrArray of
1006 * Returns: (transfer full) (nullable) (element-type utf8): array of strings.
1009 collect_strings (int argc
, GnmExprConstPtr
const *argv
,
1010 GnmEvalPos
const *ep
, CollectFlags flags
,
1013 collect_strings_t cl
;
1014 CellIterFlags iter_flags
= CELL_ITER_ALL
;
1017 /* We don't handle these flags */
1018 g_return_val_if_fail (!(flags
& COLLECT_ZERO_ERRORS
), NULL
);
1019 g_return_val_if_fail (!(flags
& COLLECT_ZERO_STRINGS
), NULL
);
1020 g_return_val_if_fail (!(flags
& COLLECT_ZEROONE_BOOLS
), NULL
);
1021 g_return_val_if_fail (!(flags
& COLLECT_ZERO_BLANKS
), NULL
);
1023 if (flags
& COLLECT_IGNORE_BLANKS
)
1024 iter_flags
= CELL_ITER_IGNORE_BLANK
;
1026 strict
= (flags
& (COLLECT_IGNORE_ERRORS
| COLLECT_ZERO_ERRORS
)) == 0;
1028 cl
.data
= g_ptr_array_new ();
1031 *error
= function_iterate_argument_values
1032 (ep
, &callback_function_collect_strings
, &cl
,
1034 strict
, iter_flags
);
1036 g_assert (VALUE_IS_ERROR (*error
));
1037 collect_strings_free (cl
.data
);
1045 * string_range_function:
1046 * @argc: number of arguments
1047 * @argv: (in) (array length=argc): function arguments
1048 * @ei: #GnmFuncEvalInfo describing evaluation context
1049 * @func: (scope call): implementation function
1050 * @flags: #CollectFlags flags describing the collection and interpretation
1051 * of values from @argv.
1052 * @func_error: A #GnmStdError to use to @func indicates an error.
1054 * This implements a Gnumeric sheet function that operates on a list of
1055 * strings. This function collects the arguments and uses @func to do
1056 * the actual computation.
1058 * Returns: (transfer full): Function result or error value.
1061 string_range_function (int argc
, GnmExprConstPtr
const *argv
,
1062 GnmFuncEvalInfo
*ei
,
1063 string_range_function_t func
,
1066 GnmStdError func_error
)
1068 GnmValue
*error
= NULL
;
1073 vals
= collect_strings (argc
, argv
, ei
->pos
, flags
, &error
);
1077 err
= func (vals
, &res
, user
);
1079 collect_strings_free (vals
);
1083 return value_new_error_std (ei
->pos
, func_error
);
1085 return value_new_string_nocopy (res
);