GETENV: check for proper UTF-8.
[gnumeric.git] / src / collect.c
blob381ef1eb07080932630d21b857bbe5895e74cf3e
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * collect.c: Helpers to collect ranges of data.
5 * Authors:
6 * Morten Welinder <terra@gnome.org>
7 * Jukka-Pekka Iivonen <iivonen@iki.fi>
8 */
10 #include <gnumeric-config.h>
11 #include "gnumeric.h"
12 #include "collect.h"
14 #include "func.h"
15 #include "application.h"
16 #include "value.h"
17 #include "expr.h"
18 #include "expr-impl.h"
19 #include "gnm-datetime.h"
20 #include "workbook.h"
21 #include "sheet.h"
22 #include "ranges.h"
23 #include "number-match.h"
24 #include <goffice/goffice.h>
25 #include <stdlib.h>
26 #include <string.h>
28 /* ------------------------------------------------------------------------- */
30 typedef struct {
31 /* key */
32 GnmValue *value;
33 CollectFlags flags;
35 /* result */
36 int n;
37 gnm_float *data;
38 GnmValue *error;
39 } SingleFloatsCacheEntry;
41 static void
42 single_floats_cache_entry_free (SingleFloatsCacheEntry *entry)
44 value_release (entry->value);
45 value_release (entry->error);
46 g_free (entry->data);
47 g_free (entry);
50 static guint
51 single_floats_cache_entry_hash (const SingleFloatsCacheEntry *entry)
53 return value_hash (entry->value) ^ (guint)entry->flags;
56 static gboolean
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 /* ------------------------------------------------------------------------- */
67 typedef struct {
68 /* key */
69 GnmValue *vx;
70 GnmValue *vy;
71 CollectFlags flags;
73 /* result */
74 int n;
75 gnm_float *data_x;
76 gnm_float *data_y;
77 GnmValue *error;
78 } PairsFloatsCacheEntry;
80 static void
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);
88 g_free (entry);
91 static guint
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;
99 static gboolean
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;
117 static void
118 clear_caches (void)
120 if (!cache_handler)
121 return;
123 g_signal_handler_disconnect (gnm_app_get_app (), cache_handler);
124 cache_handler = 0;
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;
134 static void
135 create_caches (void)
137 if (cache_handler)
138 return;
140 cache_handler =
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,
148 NULL);
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,
153 NULL);
155 total_cache_size = 0;
158 static gboolean
159 cb_prune (gpointer key, gpointer value, gpointer user)
161 return TRUE;
164 static void
165 prune_caches (void)
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,
173 cb_prune,
174 NULL);
175 g_hash_table_foreach_remove (pairs_floats_cache,
176 cb_prune,
177 NULL);
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))
187 return NULL;
189 create_caches ();
191 key.value = (GnmValue *)value;
192 key.flags = flags;
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,
199 CollectFlags flags)
201 PairsFloatsCacheEntry key;
203 if (flags & (COLLECT_INFO | COLLECT_IGNORE_SUBTOTAL))
204 return NULL;
206 create_caches ();
208 key.vx = (GnmValue *)vx;
209 key.vy = (GnmValue *)vy;
210 key.flags = flags;
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);
222 if (ce) return ce;
224 if (flags & COLLECT_ORDER_IRRELEVANT) {
225 ce = get_single_floats_cache_entry (key, flags | COLLECT_SORT);
226 if (ce)
227 return ce;
230 if (flags & COLLECT_SORT) {
231 /* FIXME: Try unsorted. */
234 return NULL;
237 static PairsFloatsCacheEntry *
238 get_or_fake_pairs_cache_entry (GnmValue const *key_x, GnmValue const *key_y,
239 CollectFlags flags,
240 GnmEvalPos const *ep)
242 PairsFloatsCacheEntry *ce;
244 ce = get_pairs_floats_cache_entry (key_x, key_y, flags);
245 if (ce) return ce;
247 /* FIXME: we should also try the pairs switched */
249 return NULL;
252 static GnmValue *
253 get_single_cache_key_from_value (GnmValue const *r, GnmEvalPos const *ep)
255 GnmValue *key;
256 GnmSheetRange sr;
257 GnmRangeRef const *rr;
258 Sheet *end_sheet;
259 int h, w;
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)
270 return NULL;
272 key = value_new_cellrange_r (sr.sheet, &sr.range);
274 return key;
277 static GnmValue *
278 get_single_cache_key (GnmExpr const *e, GnmEvalPos const *ep)
280 GnmValue *r = gnm_expr_get_range (e);
282 if (r) {
283 GnmValue *v = get_single_cache_key_from_value (r, ep);
284 value_release (r);
285 return v;
286 } else
287 return NULL;
291 /* ------------------------------------------------------------------------- */
293 static int
294 float_compare (const void *a_, const void *b_)
296 gnm_float const *a = a_;
297 gnm_float const *b = b_;
299 if (*a < *b)
300 return -1;
301 else if (*a == *b)
302 return 0;
303 else
304 return 1;
307 typedef struct {
308 guint alloc_count;
309 gnm_float *data;
310 guint count;
311 CollectFlags flags;
312 GSList *info;
313 GODateConventions const *date_conv;
314 } collect_floats_t;
316 static GnmValue *
317 callback_function_collect (GnmEvalPos const *ep, GnmValue const *value,
318 void *closure)
320 gnm_float x = 0;
321 collect_floats_t *cl = closure;
322 gboolean ignore = FALSE;
324 switch (value ? value->v_any.type : VALUE_EMPTY) {
325 case VALUE_EMPTY:
326 if (cl->flags & COLLECT_IGNORE_BLANKS)
327 ignore = TRUE;
328 else if (cl->flags & COLLECT_ZERO_BLANKS)
329 x = 0;
330 else
331 return value_new_error_VALUE (ep);
332 break;
334 case VALUE_BOOLEAN:
335 if (cl->flags & COLLECT_IGNORE_BOOLS)
336 ignore = TRUE;
337 else if (cl->flags & COLLECT_ZEROONE_BOOLS)
338 x = value_get_as_float (value);
339 else
340 return value_new_error_VALUE (ep);
341 break;
343 case VALUE_CELLRANGE :
344 case VALUE_ARRAY :
345 /* Ranges and arrays are not singleton values treat as errors */
347 case VALUE_ERROR:
348 if (cl->flags & COLLECT_IGNORE_ERRORS)
349 ignore = TRUE;
350 else if (cl->flags & COLLECT_ZERO_ERRORS)
351 x = 0;
352 else
353 return value_new_error_VALUE (ep);
354 break;
356 case VALUE_FLOAT:
357 x = value_get_as_float (value);
358 break;
360 case VALUE_STRING:
361 if (cl->flags & COLLECT_COERCE_STRINGS) {
362 GnmValue *vc = format_match_number (value_peek_string (value),
363 NULL,
364 cl->date_conv);
365 gboolean bad = !vc || VALUE_IS_BOOLEAN (vc);
366 if (vc) {
367 x = value_get_as_float (vc);
368 value_release (vc);
369 } else
370 x = 0;
372 if (bad)
373 return value_new_error_VALUE (ep);
374 } else if (cl->flags & COLLECT_IGNORE_STRINGS)
375 ignore = TRUE;
376 else if (cl->flags & COLLECT_ZERO_STRINGS)
377 x = 0;
378 else
379 return value_new_error_VALUE (ep);
380 break;
382 default:
383 g_warning ("Trouble in callback_function_collect. (%d)",
384 value->v_any.type);
385 ignore = TRUE;
388 if (ignore) {
389 if (cl->flags & COLLECT_INFO)
390 cl->info = g_slist_prepend (cl->info, GUINT_TO_POINTER (cl->count));
391 else {
392 return NULL;
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;
402 return NULL;
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
419 * in filtered rows.
420 * n: Output parameter for number of floats.
422 * Return value:
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
428 * gnm_float.
430 gnm_float *
431 collect_floats (int argc, GnmExprConstPtr const *argv,
432 GnmEvalPos const *ep, CollectFlags flags,
433 int *n, GnmValue **error, GSList **info,
434 gboolean *constp)
436 collect_floats_t cl;
437 CellIterFlags iter_flags = CELL_ITER_ALL;
438 GnmValue *key = NULL;
439 CollectFlags keyflags = flags & ~COLLECT_ORDER_IRRELEVANT;
440 gboolean strict;
442 if (constp)
443 *constp = FALSE;
445 if (info) {
446 *info = NULL;
447 g_return_val_if_fail (!(flags & COLLECT_SORT), NULL);
448 flags |= COLLECT_INFO;
449 } else {
450 if (flags & COLLECT_IGNORE_BLANKS)
451 iter_flags = CELL_ITER_IGNORE_BLANK;
452 flags &= ~COLLECT_INFO;
455 /* ---------------------------------------- */
456 /* Try cache. */
458 if (argc == 1 &&
459 (flags & (COLLECT_INFO | COLLECT_IGNORE_SUBTOTAL)) == 0) {
460 key = get_single_cache_key (argv[0], ep);
462 if (key) {
463 SingleFloatsCacheEntry *ce =
464 get_or_fake_cache_entry (key, keyflags, ep);
465 if (ce) {
466 value_release (key);
467 if (ce->error) {
468 *error = value_dup (ce->error);
469 return NULL;
471 *n = ce->n;
472 if (constp) {
473 *constp = TRUE;
474 return ce->data;
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;
488 cl.alloc_count = 0;
489 cl.data = NULL;
490 cl.count = 0;
491 cl.flags = flags;
492 cl.info = NULL;
493 cl.date_conv = workbook_date_conv (ep->sheet->workbook);
495 *error = function_iterate_argument_values
496 (ep, &callback_function_collect, &cl,
497 argc, argv,
498 strict, iter_flags);
499 if (*error) {
500 g_assert (VALUE_IS_ERROR (*error));
501 g_free (cl.data);
502 cl.data = NULL;
503 cl.count = 0;
504 g_slist_free (cl.info);
505 cl.info = NULL;
506 } else {
507 if (cl.data == NULL) {
508 cl.alloc_count = 1;
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]),
514 float_compare);
518 if (info)
519 *info = cl.info;
520 *n = cl.count;
522 if (key) {
523 SingleFloatsCacheEntry *ce = g_new (SingleFloatsCacheEntry, 1);
524 SingleFloatsCacheEntry *ce2;
525 ce->value = key;
526 ce->flags = keyflags;
527 ce->n = *n;
528 ce->error = value_dup (*error);
529 if (cl.data == NULL)
530 ce->data = NULL;
531 else if (constp) {
532 *constp = TRUE;
533 ce->data = cl.data;
534 } else
535 ce->data = g_memdup (cl.data, MAX (1, *n) * sizeof (gnm_float));
536 prune_caches ();
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.
542 * See bug 627079.
544 ce2 = g_hash_table_lookup (single_floats_cache, ce);
545 if (ce2)
546 total_cache_size -= 1 + ce2->n;
548 g_hash_table_replace (single_floats_cache, ce, ce);
549 total_cache_size += 1 + *n;
551 return cl.data;
554 /* ------------------------------------------------------------------------- */
555 /* Like collect_floats, but takes a value instead of an expression list.
556 Presumably most useful when the value is an array. */
558 gnm_float *
559 collect_floats_value (GnmValue const *val, GnmEvalPos const *ep,
560 CollectFlags flags, int *n, GnmValue **error)
562 GnmExpr expr_val;
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:
572 * @val: #GnmValue
573 * @ep: #GnmEvalPos
574 * @flags: #CollectFlags
575 * @n:
576 * @info: (element-type void):
577 * @error:
579 * Like collect_floats_value, but keeps info on missing values
582 gnm_float *
583 collect_floats_value_with_info (GnmValue const *val, GnmEvalPos const *ep,
584 CollectFlags flags, int *n, GSList **info,
585 GnmValue **error)
587 GnmExpr expr_val;
588 GnmExprConstPtr argv[1] = { &expr_val };
589 gnm_float *res;
591 gnm_expr_constant_init (&expr_val.constant, val);
592 res = collect_floats (1, argv, ep, flags, n, error, info, NULL);
594 if (info)
595 *info = g_slist_reverse (*info);
597 return res;
601 /* ------------------------------------------------------------------------- */
604 * float_range_function:
605 * @argc:
606 * @argv:
607 * @ei:
608 * @func: (scope call):
609 * @flags:
610 * @func_error:
612 * Returns: (transfer full):
614 GnmValue *
615 float_range_function (int argc, GnmExprConstPtr const *argv,
616 GnmFuncEvalInfo *ei,
617 float_range_function_t func,
618 CollectFlags flags,
619 GnmStdError func_error)
621 GnmValue *error = NULL;
622 gnm_float *vals, res;
623 int n, err;
624 gboolean constp;
626 vals = collect_floats (argc, argv, ei->pos, flags, &n, &error,
627 NULL, &constp);
628 if (!vals)
629 return error;
631 err = func (vals, n, &res);
632 if (!constp) g_free (vals);
634 if (err)
635 return value_new_error_std (ei->pos, func_error);
636 else
637 return value_new_float (res);
640 /* ------------------------------------------------------------------------- */
643 * gnm_slist_sort_merge:
644 * @list_1: (element-type void): a sorted list of ints with no duplicates
645 * @list_2: (element-type void): another one
647 * gnm_slist_sort_merge returns a new sorted list with all elements
648 * from both @list_1 and @list_2. Duplicates are destroyed. @list1 and @list2
649 * are not anymore valid afterwards since their elements are in the new list
650 * or have been destroyed, in case of duplicates.
652 * Returns: (element-type void) (transfer container): the new list.
655 GSList *
656 gnm_slist_sort_merge (GSList *l1,
657 GSList *l2)
659 GSList list, *l;
661 l = &list;
663 while (l1 && l2) {
664 if (GPOINTER_TO_UINT (l1->data) <= GPOINTER_TO_UINT (l2->data)) {
665 if (GPOINTER_TO_UINT (l1->data) == GPOINTER_TO_UINT (l2->data)) {
666 /* remove duplicates */
667 GSList *m = l2;
668 l2 = l2->next;
669 m->next = NULL;
670 g_slist_free_1 (m);
672 l = l->next = l1;
673 l1 = l1->next;
674 } else {
675 l = l->next = l2;
676 l2 = l2->next;
679 l->next = l1 ? l1 : l2;
681 return list.next;
686 * gnm_strip_missing:
687 * @data:
688 * @missing: (element-type void):
691 void
692 gnm_strip_missing (gnm_float *data, int *n, GSList *missing)
694 unsigned src, dst;
696 if (missing == NULL)
697 return;
699 for (src = dst = 0; (int)dst < *n; src++) {
700 if (missing && src == GPOINTER_TO_UINT (missing->data)) {
701 missing = missing->next;
702 (*n)--;
703 } else {
704 data[dst] = data[src];
705 dst++;
710 static PairsFloatsCacheEntry *
711 collect_float_pairs_ce (GnmValue const *vx, GnmValue const *vy,
712 GnmEvalPos const *ep, CollectFlags flags)
714 PairsFloatsCacheEntry *ce = g_new0 (PairsFloatsCacheEntry, 1);
715 GSList *missing0 = NULL, *missing1 = NULL;
716 int n0, n1;
718 ce->flags = flags;
720 ce->data_x = collect_floats_value_with_info (vx, ep, flags,
721 &n0, &missing0, &ce->error);
722 if (ce->error)
723 goto err;
725 ce->data_y = collect_floats_value_with_info (vy, ep, flags,
726 &n1, &missing1, &ce->error);
728 if (ce->error)
729 goto err;
731 if (n0 != n1) {
732 ce->n = -1;
733 goto err;
736 if (missing0 || missing1) {
737 missing0 = gnm_slist_sort_merge (missing0, missing1);
738 missing1 = NULL;
739 gnm_strip_missing (ce->data_x, &n0, missing0);
740 gnm_strip_missing (ce->data_y, &n1, missing0);
742 ce->n = n0;
744 err:
745 if (ce->n <= 0) {
746 g_free (ce->data_x);
747 ce->data_x = NULL;
748 g_free (ce->data_y);
749 ce->data_y = NULL;
752 g_slist_free (missing0);
753 g_slist_free (missing1);
755 return ce;
759 * collect_float_pairs:
760 * @v0: value describing first data range
761 * @v1: value describing second data range
762 * @ep: evaluation position
763 * @flags: flags describing how to handle value types
764 * @xs0: return location for first data vector
765 * @xs1: return location for second data vector
766 * @n: return location for number of data points
767 * @constp: optional return location for an indicator of the return vectors
768 * being owned by this function as opposed to the normal copy owned by the
769 * caller.
771 * If @n is not positive upon return, no data has been allocated.
772 * If @n is negative upon return, the two ranges had different
773 * sizes.
775 GnmValue *
776 collect_float_pairs (GnmValue const *vx, GnmValue const *vy,
777 GnmEvalPos const *ep, CollectFlags flags,
778 gnm_float **xs0, gnm_float **xs1, int *n,
779 gboolean *constp)
781 GnmValue *key_x = NULL;
782 GnmValue *key_y = NULL;
783 PairsFloatsCacheEntry *ce = NULL;
784 gboolean use_cache, free_keys = TRUE;
786 if (VALUE_IS_CELLRANGE (vx))
787 key_x = get_single_cache_key_from_value (vx, ep);
788 if (VALUE_IS_CELLRANGE (vy))
789 key_y = get_single_cache_key_from_value (vy, ep);
791 if ((use_cache = (key_x && key_y)))
792 ce = get_or_fake_pairs_cache_entry (key_x, key_y, flags, ep);
794 if (!ce) {
795 ce = collect_float_pairs_ce (vx, vy, ep, flags);
796 if (use_cache) {
797 PairsFloatsCacheEntry *ce2;
798 ce->vx = key_x;
799 ce->vy = key_y;
800 free_keys = FALSE;
803 * We looked for the entry earlier and it was not there.
804 * However, sub-calculation might have added it so be careful
805 * to adjust sizes and replace the not-so-old entry.
806 * See bug 627079.
808 ce2 = g_hash_table_lookup (pairs_floats_cache, ce);
809 if (ce2)
810 total_cache_size -= 1 + ce2->n;
812 g_hash_table_replace (pairs_floats_cache, ce, ce);
813 total_cache_size += 1 + ce->n;
817 if (free_keys) {
818 value_release (key_x);
819 value_release (key_y);
822 if (ce == NULL)
823 return value_new_error_VALUE (ep);
824 else {
825 if (ce->error) {
826 if (use_cache)
827 return value_dup (ce->error);
828 else {
829 GnmValue *ret = ce->error;
830 ce->error = NULL;
831 pairs_floats_cache_entry_free (ce);
832 return ret;
835 *n = ce->n;
836 if (ce->n <= 0) {
837 if (!use_cache)
838 pairs_floats_cache_entry_free (ce);
839 *xs0 = NULL;
840 *xs1 = NULL;
841 if (constp)
842 *constp = FALSE;
843 return NULL;
845 if (use_cache) {
846 if (constp) {
847 *xs0 = ce->data_x;
848 *xs1 = ce->data_y;
849 *constp = TRUE;
850 } else {
851 *xs0 = g_memdup (ce->data_x, *n * sizeof (gnm_float));
852 *xs1 = g_memdup (ce->data_y, *n * sizeof (gnm_float));
854 } else {
855 if (constp)
856 *constp = FALSE;
857 *xs0 = ce->data_x;
858 *xs1 = ce->data_y;
859 ce->data_x = NULL;
860 ce->data_y = NULL;
861 pairs_floats_cache_entry_free (ce);
863 return NULL;
868 * float_range_function2d:
869 * @val0:
870 * @val1:
871 * @ei:
872 * @func: (scope call):
873 * @flags:
874 * @func_error:
876 * Returns: (transfer full):
878 GnmValue *
879 float_range_function2d (GnmValue const *val0, GnmValue const *val1,
880 GnmFuncEvalInfo *ei,
881 float_range_function2d_t func,
882 CollectFlags flags,
883 GnmStdError func_error,
884 gpointer data)
886 gnm_float *vals0, *vals1;
887 int n;
888 GnmValue *res;
889 gnm_float fres;
890 gboolean constp = FALSE;
892 res = collect_float_pairs (val0, val1, ei->pos, flags,
893 &vals0, &vals1, &n, &constp);
894 if (res)
895 return res;
897 if (n <= 0)
898 return value_new_error_std (ei->pos, func_error);
900 if (func (vals0, vals1, n, &fres, data))
901 res = value_new_error_std (ei->pos, func_error);
902 else
903 res = value_new_float (fres);
905 if (!constp) {
906 g_free (vals0);
907 g_free (vals1);
909 return res;
913 * float_range_function2:
914 * @val0:
915 * @val1:
916 * @ei:
917 * @func: (scope call):
918 * @flags:
919 * @func_error:
921 * Returns: (transfer full):
923 GnmValue *
924 float_range_function2 (GnmValue const *val0, GnmValue const *val1,
925 GnmFuncEvalInfo *ei,
926 float_range_function2_t func,
927 CollectFlags flags,
928 GnmStdError func_error)
930 return float_range_function2d (val0, val1, ei,
931 (float_range_function2d_t)func,
932 flags,
933 func_error,
934 NULL);
937 /* ------------------------------------------------------------------------- */
938 /* ------------------------------------------------------------------------- */
940 typedef struct {
941 GPtrArray *data;
942 CollectFlags flags;
943 } collect_strings_t;
945 static GnmValue *
946 callback_function_collect_strings (GnmEvalPos const *ep, GnmValue const *value,
947 void *closure)
949 char *text;
950 collect_strings_t *cl = closure;
952 if (VALUE_IS_EMPTY (value)) {
953 if (cl->flags & COLLECT_IGNORE_BLANKS)
954 text = NULL;
955 else
956 text = g_strdup ("");
957 } else
958 text = value_get_as_string (value);
960 if (text)
961 g_ptr_array_add (cl->data, text);
963 return NULL;
966 static void
967 collect_strings_free (GPtrArray *data)
969 g_ptr_array_foreach (data, (GFunc)g_free, NULL);
970 g_ptr_array_free (data, TRUE);
974 * collect_strings:
976 * exprlist: List of expressions to evaluate.
977 * ep: Current location (for resolving relative cells).
978 * flags: 0 or COLLECT_IGNORE_BLANKS
980 * Return value:
981 * NULL in case of error, error will be set
982 * Non-NULL in case of success.
984 * Evaluate a list of expressions and return the result as a GPtrArray of
985 * strings.
988 static GPtrArray *
989 collect_strings (int argc, GnmExprConstPtr const *argv,
990 GnmEvalPos const *ep, CollectFlags flags,
991 GnmValue **error)
993 collect_strings_t cl;
994 CellIterFlags iter_flags = CELL_ITER_ALL;
995 gboolean strict;
997 /* We don't handle these flags */
998 g_return_val_if_fail (!(flags & COLLECT_ZERO_ERRORS), NULL);
999 g_return_val_if_fail (!(flags & COLLECT_ZERO_STRINGS), NULL);
1000 g_return_val_if_fail (!(flags & COLLECT_ZEROONE_BOOLS), NULL);
1001 g_return_val_if_fail (!(flags & COLLECT_ZERO_BLANKS), NULL);
1003 if (flags & COLLECT_IGNORE_BLANKS)
1004 iter_flags = CELL_ITER_IGNORE_BLANK;
1006 strict = (flags & (COLLECT_IGNORE_ERRORS | COLLECT_ZERO_ERRORS)) == 0;
1008 cl.data = g_ptr_array_new ();
1009 cl.flags = flags;
1011 *error = function_iterate_argument_values
1012 (ep, &callback_function_collect_strings, &cl,
1013 argc, argv,
1014 strict, iter_flags);
1015 if (*error) {
1016 g_assert (VALUE_IS_ERROR (*error));
1017 collect_strings_free (cl.data);
1018 return NULL;
1021 return cl.data;
1025 * string_range_function:
1026 * @argc:
1027 * @argv:
1028 * @ei:
1029 * @func: (scope call):
1030 * @flags:
1031 * @func_error:
1033 * Returns: (transfer full):
1035 GnmValue *
1036 string_range_function (int argc, GnmExprConstPtr const *argv,
1037 GnmFuncEvalInfo *ei,
1038 string_range_function_t func,
1039 gpointer user,
1040 CollectFlags flags,
1041 GnmStdError func_error)
1043 GnmValue *error = NULL;
1044 GPtrArray *vals;
1045 char *res = NULL;
1046 int err;
1048 vals = collect_strings (argc, argv, ei->pos, flags, &error);
1049 if (!vals)
1050 return error;
1052 err = func (vals, &res, user);
1054 collect_strings_free (vals);
1056 if (err) {
1057 g_free (res);
1058 return value_new_error_std (ei->pos, func_error);
1059 } else {
1060 return value_new_string_nocopy (res);