ssdiff: move comparison engine into its own file.
[gnumeric.git] / src / expr-name.c
blobb6fd0802e8e375fd374be4a8609091ae9b68ccce
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * expr-name.c: Supported named expressions
5 * Author:
6 * Jody Goldberg <jody@gnome.org>
8 * Based on work by:
9 * Michael Meeks <michael@ximian.com>
12 #include <gnumeric-config.h>
13 #include <glib/gi18n-lib.h>
14 #include <string.h>
15 #include "gnumeric.h"
16 #include "expr-name.h"
18 #include "dependent.h"
19 #include "value.h"
20 #include "workbook-priv.h"
21 #include "expr.h"
22 #include "sheet.h"
23 #include "ranges.h"
24 #include "gutils.h"
25 #include "sheet-style.h"
27 #include <goffice/goffice.h>
30 static gboolean
31 expr_name_validate_r1c1 (const char *name)
33 const char *p = name;
34 gint i;
36 if (p[0] != 'R' && p[0] != 'r')
37 return TRUE;
38 p++;
39 /* no need to worry about [] since they are not alphanumeric */
40 for (i = 0; p[0] && g_ascii_isdigit (p[0]); p = g_utf8_next_char (p))
41 i++;
42 if (i==0)
43 return TRUE;
44 if (p[0] != 'C' && p[0] != 'c')
45 return TRUE;
46 p++;
47 for (i = 0; p[0] && g_ascii_isdigit (p[0]); p = g_utf8_next_char (p))
48 i++;
49 if (i==0)
50 return TRUE;
51 return (p[0] != '\0');
54 static gboolean
55 expr_name_validate_a1 (const char *name)
57 const char *p = name;
58 gint i;
60 for (i = 0; *p && g_ascii_isalpha(p[0]);
61 p = g_utf8_next_char (p))
62 i++;
63 if (i==0 || i>4) /* We want to allow "total2010" and it */
64 /* is unlikely to have more than 456976 */
65 /* columns atm */
66 return TRUE;
67 for (i = 0; *p && g_ascii_isdigit (p[0]);
68 p = g_utf8_next_char (p))
69 i++;
70 if (i==0)
71 return TRUE;
72 return (*p != '\0');
75 /**
76 * expr_name_validate:
77 * @name: tentative name
79 * returns TRUE if the given name is valid, FALSE otherwise.
81 gboolean
82 expr_name_validate (const char *name)
84 const char *p;
85 GnmValue *v;
87 g_return_val_if_fail (name != NULL, FALSE);
89 if (name[0] == 0)
90 return FALSE;
92 v = value_new_from_string (VALUE_BOOLEAN, name, NULL, TRUE);
93 if (!v)
94 v = value_new_from_string (VALUE_BOOLEAN, name, NULL, FALSE);
95 if (v) {
96 value_release (v);
97 return FALSE;
100 /* Hmm... Now what? */
101 if (!g_unichar_isalpha (g_utf8_get_char (name)) &&
102 name[0] != '_')
103 return FALSE;
105 for (p = name; *p; p = g_utf8_next_char (p)) {
106 if (!g_unichar_isalnum (g_utf8_get_char (p)) &&
107 p[0] != '_')
108 return FALSE;
111 /* Make sure it's not A1 etc.*/
112 /* Note that we can't use our regular parsers */
113 /* since we also have to avoid names that may become */
114 /* sensible when the sheet size changes. */
115 if (!expr_name_validate_a1 (name))
116 return FALSE;
118 /* What about R1C1? */
119 if (!expr_name_validate_r1c1 (name))
120 return FALSE;
122 return TRUE;
126 static void
127 cb_nexpr_remove (GnmNamedExpr *nexpr)
129 g_return_if_fail (nexpr->scope != NULL);
131 nexpr->scope = NULL;
132 expr_name_set_expr (nexpr, NULL);
133 expr_name_unref (nexpr);
136 static void
137 cb_collect_name_deps (gpointer key, G_GNUC_UNUSED gpointer value,
138 gpointer user_data)
140 GSList **list = user_data;
141 *list = g_slist_prepend (*list, key);
144 static GSList *
145 expr_name_unlink_deps (GnmNamedExpr *nexpr)
147 GSList *ptr, *deps = NULL;
149 if (nexpr->dependents == NULL)
150 return NULL;
152 g_hash_table_foreach (nexpr->dependents, cb_collect_name_deps, &deps);
154 /* pull them out */
155 for (ptr = deps ; ptr != NULL ; ptr = ptr->next) {
156 GnmDependent *dep = ptr->data;
157 if (dependent_is_linked (dep))
158 dependent_unlink (dep);
160 return deps;
163 static void
164 expr_name_relink_deps (GnmNamedExpr *nexpr)
166 GSList *deps = NULL;
168 if (nexpr->dependents == NULL)
169 return;
171 g_hash_table_foreach (nexpr->dependents, cb_collect_name_deps, &deps);
172 dependents_link (deps);
173 g_slist_free (deps);
176 static guint
177 fake_go_string_hash (gconstpointer s_)
179 const GOString *s = s_;
180 return g_str_hash (s->str);
183 static gboolean
184 fake_go_string_equal (gconstpointer a_, gconstpointer b_)
186 const GOString *a = a_;
187 const GOString *b = b_;
188 return g_str_equal (a->str, b->str);
192 struct _GnmNamedExprCollection {
193 /* all the defined names */
194 GHashTable *names;
196 /* placeholders for references to undefined names */
197 GHashTable *placeholders;
199 /* <private> */
200 unsigned ref_count; /* boxed type */
204 * gnm_named_expr_collection_new:
206 * Returns: (transfer full): the newly allocated #GnmNamedExprCollection/
208 GnmNamedExprCollection *
209 gnm_named_expr_collection_new (void)
211 GnmNamedExprCollection *res = g_new (GnmNamedExprCollection, 1);
213 res->names = g_hash_table_new_full
214 (fake_go_string_hash, fake_go_string_equal,
215 NULL, (GDestroyNotify) cb_nexpr_remove);
216 res->placeholders = g_hash_table_new_full
217 (fake_go_string_hash, fake_go_string_equal,
218 NULL, (GDestroyNotify) cb_nexpr_remove);
219 res->ref_count = 1;
221 return res;
225 * gnm_named_expr_collection_free:
226 * @names: The collection of names
228 * Frees names defined in the local scope.
229 * NOTE : THIS DOES NOT INVALIDATE NAMES THAT REFER
230 * TO THIS SCOPE.
231 * eg
232 * in scope sheet2 we have a name that refers
233 * to sheet1. That will remain!
235 void
236 gnm_named_expr_collection_free (GnmNamedExprCollection *names)
238 if (names != NULL && names->ref_count-- < 2) {
239 g_hash_table_destroy (names->names);
240 g_hash_table_destroy (names->placeholders);
241 g_free (names);
245 static GnmNamedExprCollection *
246 gnm_named_expr_collection_ref (GnmNamedExprCollection *names)
248 names->ref_count++;
249 return names;
252 void
253 gnm_named_expr_collection_dump (GnmNamedExprCollection *names, const char *id)
255 g_printerr ("Named collection %s\n", id);
256 if (!names) {
257 g_printerr (" Empty\n");
258 return;
261 if (names->names && g_hash_table_size (names->names)) {
262 GHashTableIter hiter;
263 gpointer key, value;
265 g_printerr (" Defined names:\n");
266 g_hash_table_iter_init (&hiter, names->names);
267 while (g_hash_table_iter_next (&hiter, &key, &value)) {
268 const GOString *name = key;
269 GnmNamedExpr const *nexpr = value;
270 g_printerr (" [%s] =>\n", name->str);
271 if (name != nexpr->name)
272 g_printerr (" Weird keys: %p vs %p\n",
273 name, nexpr->name);
277 if (names->placeholders && g_hash_table_size (names->placeholders)) {
278 GHashTableIter hiter;
279 gpointer key, value;
281 g_printerr (" Defined placeholders:\n");
282 g_hash_table_iter_init (&hiter, names->placeholders);
283 while (g_hash_table_iter_next (&hiter, &key, &value)) {
284 const GOString *name = key;
285 GnmNamedExpr const *nexpr = value;
286 g_printerr (" [%s] =>\n", name->str);
287 if (name != nexpr->name)
288 g_printerr (" Weird keys: %p vs %p\n",
289 name, nexpr->name);
294 gboolean
295 gnm_named_expr_collection_sanity_check (GnmNamedExprCollection *names,
296 const char *id)
298 gboolean err = FALSE;
299 g_printerr ("Checking sanity for container %s\n", id);
300 if (names->names) {
301 GHashTableIter hiter;
302 gpointer key, value;
304 g_hash_table_iter_init (&hiter, names->names);
305 while (g_hash_table_iter_next (&hiter, &key, &value)) {
306 const GOString *name = key;
307 GnmNamedExpr const *nexpr = value;
308 if (name != nexpr->name) {
309 err = TRUE;
310 g_printerr ("Container %s has strange defined name\n",
311 id);
312 g_printerr (" key is %p [%s]\n",
313 name, name->str);
314 g_printerr (" target's name is %p [%s]\n",
315 nexpr->name, nexpr->name->str);
319 return err;
322 GType
323 gnm_named_expr_collection_get_type (void)
325 static GType t = 0;
327 if (t == 0) {
328 t = g_boxed_type_register_static ("GnmNamedExprCollection",
329 (GBoxedCopyFunc)gnm_named_expr_collection_ref,
330 (GBoxedFreeFunc)gnm_named_expr_collection_free);
332 return t;
335 static void
336 cb_unlink_all_names (G_GNUC_UNUSED gpointer key,
337 gpointer value,
338 G_GNUC_UNUSED gpointer user_data)
340 GnmNamedExpr *nexpr = value;
341 GSList *deps = expr_name_unlink_deps (nexpr);
342 g_slist_free (deps);
345 void
346 gnm_named_expr_collection_unlink (GnmNamedExprCollection *names)
348 if (!names)
349 return;
351 g_hash_table_foreach (names->names,
352 cb_unlink_all_names,
353 NULL);
356 static void
357 cb_relink_all_names (G_GNUC_UNUSED gpointer key,
358 gpointer value,
359 G_GNUC_UNUSED gpointer user_data)
361 GnmNamedExpr *nexpr = value;
362 expr_name_relink_deps (nexpr);
365 void
366 gnm_named_expr_collection_relink (GnmNamedExprCollection *names)
368 if (!names)
369 return;
371 g_hash_table_foreach (names->names,
372 cb_relink_all_names,
373 NULL);
376 GnmNamedExpr *
377 gnm_named_expr_collection_lookup (GnmNamedExprCollection const *scope,
378 char const *name)
380 if (scope != NULL) {
381 GOString fake_name;
382 GnmNamedExpr *nexpr;
384 fake_name.str = name;
385 nexpr = g_hash_table_lookup (scope->names, &fake_name);
386 if (nexpr == NULL)
387 nexpr = g_hash_table_lookup (scope->placeholders,
388 &fake_name);
389 return nexpr;
390 } else
391 return NULL;
394 static void
395 cb_list_names (G_GNUC_UNUSED gpointer key,
396 gpointer value,
397 gpointer user_data)
399 GSList **pres = user_data;
400 GO_SLIST_PREPEND (*pres, value);
404 * gnm_named_expr_collection_list:
405 * @scope: #GnmNamedExprCollection
407 * Returns: (element-type GnmNamedExpr) (transfer container):
409 GSList *
410 gnm_named_expr_collection_list (GnmNamedExprCollection const *scope)
412 GSList *res = NULL;
413 if (scope) {
414 g_hash_table_foreach (scope->names,
415 cb_list_names,
416 &res);
418 return res;
421 static void
422 gnm_named_expr_collection_insert (GnmNamedExprCollection *scope,
423 GnmNamedExpr *nexpr)
425 if (gnm_debug_flag ("names")) {
426 char *scope_name = nexpr->pos.sheet
427 ? g_strdup_printf ("sheet %s", nexpr->pos.sheet->name_quoted)
428 : g_strdup ("workbook");
429 g_printerr ("Inserting name %s into its %s container%s\n",
430 nexpr->name->str,
431 scope_name,
432 nexpr->is_placeholder ? " as a placeholder" : "");
433 g_free (scope_name);
436 /* name can be active at this point, eg we are converting a
437 * placeholder, or changing a scope */
438 nexpr->scope = scope;
439 g_hash_table_replace
440 (nexpr->is_placeholder ? scope->placeholders : scope->names,
441 (gpointer)nexpr->name, nexpr);
444 typedef struct {
445 Sheet const *sheet;
446 GnmRange const *r;
447 GnmNamedExpr *res;
448 } CheckName;
450 static void
451 cb_check_name (G_GNUC_UNUSED gpointer key, GnmNamedExpr *nexpr,
452 CheckName *user)
454 GnmValue *v;
456 if (nexpr->scope == NULL || nexpr->is_hidden || !nexpr->texpr)
457 return;
459 v = gnm_expr_top_get_range (nexpr->texpr);
460 if (v != NULL) {
461 if (VALUE_IS_CELLRANGE (v)) {
462 GnmRangeRef const *ref = &v->v_range.cell;
463 if (!ref->a.col_relative &&
464 !ref->b.col_relative &&
465 !ref->a.row_relative &&
466 !ref->b.row_relative &&
467 eval_sheet (ref->a.sheet, user->sheet) == user->sheet &&
468 eval_sheet (ref->b.sheet, user->sheet) == user->sheet &&
469 MIN (ref->a.col, ref->b.col) == user->r->start.col &&
470 MAX (ref->a.col, ref->b.col) == user->r->end.col &&
471 MIN (ref->a.row, ref->b.row) == user->r->start.row &&
472 MAX (ref->a.row, ref->b.row) == user->r->end.row)
473 user->res = nexpr;
475 value_release (v);
479 static GnmNamedExpr *
480 gnm_named_expr_collection_check (GnmNamedExprCollection *scope,
481 Sheet const *sheet, GnmRange const *r)
483 CheckName user;
485 if (scope == NULL)
486 return NULL;
488 user.sheet = sheet;
489 user.r = r;
490 user.res = NULL;
492 g_hash_table_foreach (scope->names, (GHFunc)cb_check_name, &user);
493 return user.res;
497 * gnm_named_expr_collection_foreach:
498 * @names: #GnmNamedExprCollection
499 * @func: (scope call):
500 * @data: user data.
502 * Iterate over all names, including placeholders.
504 void
505 gnm_named_expr_collection_foreach (GnmNamedExprCollection *names,
506 GHFunc func,
507 gpointer data)
509 g_hash_table_foreach (names->names, func, data);
510 g_hash_table_foreach (names->placeholders, func, data);
513 /******************************************************************************/
516 * expr_name_handle_references:
518 * Register or unregister a name with
519 * all of the sheets it explicitly references. This is necessary
520 * because names are not dependents, and if they reference a deleted
521 * sheet we will not notice.
523 static void
524 expr_name_handle_references (GnmNamedExpr *nexpr, gboolean add)
526 GSList *sheets, *ptr;
528 sheets = gnm_expr_top_referenced_sheets (nexpr->texpr);
530 for (ptr = sheets ; ptr != NULL ; ptr = ptr->next) {
531 Sheet *sheet = ptr->data;
532 GnmNamedExpr *found;
534 /* Implicit reference. */
535 if (!sheet)
536 continue;
538 /* No need to do anything during destruction */
539 if (sheet->deps == NULL)
540 continue;
542 found = g_hash_table_lookup (sheet->deps->referencing_names, nexpr);
543 if (add) {
544 if (found == NULL) {
545 g_hash_table_insert (sheet->deps->referencing_names, nexpr, nexpr);
546 } else {
547 g_warning ("Name being registered multiple times ?");
549 } else {
550 if (found == NULL) {
551 g_warning ("Unregistered name being removed?");
552 } else {
553 g_hash_table_remove (sheet->deps->referencing_names, nexpr);
557 g_slist_free (sheets);
562 * expr_name_lookup:
563 * @pos:
564 * @name:
566 * lookup but do not reference a named expression.
568 GnmNamedExpr *
569 expr_name_lookup (GnmParsePos const *pp, char const *name)
571 GnmNamedExpr *res = NULL;
572 Sheet const *sheet = NULL;
573 Workbook const *wb = NULL;
575 g_return_val_if_fail (name != NULL, NULL);
577 if (pp != NULL) {
578 sheet = pp->sheet;
579 wb = (sheet != NULL) ? sheet->workbook : pp->wb;
582 if (sheet != NULL && sheet->names != NULL)
583 res = gnm_named_expr_collection_lookup (sheet->names, name);
584 if (res == NULL && wb != NULL && wb->names != NULL)
585 res = gnm_named_expr_collection_lookup (wb->names, name);
586 return res;
590 * expr_name_new:
591 * @name:
593 * Creates a new name without linking it into any container.
595 GnmNamedExpr *
596 expr_name_new (char const *name)
598 GnmNamedExpr *nexpr;
600 g_return_val_if_fail (name != NULL, NULL);
602 nexpr = g_new0 (GnmNamedExpr,1);
604 nexpr->ref_count = 1;
605 nexpr->name = go_string_new (name);
606 nexpr->texpr = NULL;
607 nexpr->dependents = NULL;
608 nexpr->is_placeholder = TRUE;
609 nexpr->is_hidden = FALSE;
610 nexpr->is_permanent = FALSE;
611 nexpr->is_editable = TRUE;
612 nexpr->scope = NULL;
614 if (gnm_debug_flag ("names"))
615 g_printerr ("Created new name %s\n", name);
617 return nexpr;
620 struct cb_name_loop_check {
621 /* One of these */
622 char const *name;
623 GnmNamedExpr *nexpr;
625 gboolean stop_at_name;
626 gboolean res;
629 static GnmExpr const *
630 cb_name_loop_check (GnmExpr const *expr, GnmExprWalk *data)
632 struct cb_name_loop_check *args = data->user;
634 GnmNamedExpr const *nexpr2 = gnm_expr_get_name (expr);
635 if (nexpr2) {
636 if ((args->name && !strcmp (nexpr2->name->str, args->name)) ||
637 args->nexpr == nexpr2 ||
638 (!args->stop_at_name && nexpr2->texpr &&
639 /* Is the following right? It drops args->nexpr */
640 expr_name_check_for_loop (args->name, nexpr2->texpr))) {
641 args->res = TRUE;
642 data->stop = TRUE;
646 return NULL;
650 * NB. if we already have a circular reference in addition
651 * to this one we are checking we will come to serious grief.
653 gboolean
654 expr_name_check_for_loop (char const *name, GnmExprTop const *texpr)
656 struct cb_name_loop_check args;
658 g_return_val_if_fail (texpr != NULL, TRUE);
660 args.name = name;
661 args.nexpr = NULL;
662 args.stop_at_name = FALSE;
663 args.res = FALSE;
664 gnm_expr_walk (texpr->expr, cb_name_loop_check, &args);
665 return args.res;
668 static void
669 expr_name_queue_deps (GnmNamedExpr *nexpr)
671 if (nexpr->dependents)
672 g_hash_table_foreach (nexpr->dependents,
673 (GHFunc)dependent_queue_recalc,
674 NULL);
678 * expr_name_add:
679 * @pp:
680 * @name:
681 * @texpr: if texpr == NULL then create a placeholder with value #NAME?
682 * @error_msg:
683 * @link_to_container:
685 * Absorbs the reference to @texpr.
686 * If @error_msg is non NULL it may hold a pointer to a translated descriptive
687 * string. NOTE : caller is responsible for freeing the error message.
689 * The reference semantics of the new expression are
690 * 1) new names with @link_to_container TRUE are referenced by the container.
691 * The caller DOES NOT OWN a reference to the result, and needs to add their
692 * own.
693 * 2) if @link_to_container is FALSE the caller DOES OWN a reference, and
694 * can free the result by unrefing the name.
696 GnmNamedExpr *
697 expr_name_add (GnmParsePos const *pp, char const *name,
698 GnmExprTop const *texpr, char **error_msg,
699 gboolean link_to_container,
700 GnmNamedExpr *stub)
702 GnmNamedExpr *nexpr = NULL;
703 GnmNamedExprCollection *scope = NULL;
704 GOString fake_name;
706 g_return_val_if_fail (pp != NULL, NULL);
707 g_return_val_if_fail (pp->sheet != NULL || pp->wb != NULL, NULL);
708 g_return_val_if_fail (name != NULL, NULL);
709 g_return_val_if_fail (stub == NULL || stub->is_placeholder, NULL);
711 fake_name.str = name;
713 if (gnm_debug_flag ("names")) {
714 char *str = gnm_expr_top_as_string (texpr, pp, NULL);
715 g_printerr ("Adding Name=[%s] texpr=[%s] stub=[%s]\n",
716 name, str, stub ? expr_name_name (stub) : "-");
717 g_free (str);
720 if (texpr != NULL &&
721 (expr_name_check_for_loop (name, texpr) ||
722 (stub && expr_name_check_for_loop (expr_name_name (stub), texpr)))) {
723 gnm_expr_top_unref (texpr);
724 if (error_msg)
725 *error_msg = g_strdup_printf (_("'%s' has a circular reference"), name);
726 return NULL;
729 scope = (pp->sheet != NULL) ? pp->sheet->names : pp->wb->names;
730 /* see if there was a place holder */
731 nexpr = g_hash_table_lookup (scope->placeholders, &fake_name);
732 if (nexpr != NULL) {
733 if (texpr == NULL) {
734 /* there was already a placeholder for this */
735 if (!link_to_container)
736 expr_name_ref (nexpr);
737 return nexpr;
740 /* convert the placeholder into a real name */
741 g_hash_table_steal (scope->placeholders, &fake_name);
742 nexpr->is_placeholder = FALSE;
743 } else {
744 nexpr = g_hash_table_lookup (scope->names, &fake_name);
745 /* If this is a permanent name, we may be adding it */
746 /* on opening of a file, although */
747 /* the name is already in place. */
748 if (nexpr != NULL) {
749 if (nexpr->is_permanent)
750 link_to_container = FALSE;
751 else {
752 if (error_msg != NULL)
753 *error_msg = (pp->sheet != NULL)
754 ? g_strdup_printf (_("'%s' is already defined in sheet"), name)
755 : g_strdup_printf (_("'%s' is already defined in workbook"), name);
757 gnm_expr_top_unref (texpr);
758 return NULL;
763 if (error_msg)
764 *error_msg = NULL;
766 if (nexpr == NULL) {
767 if (stub != NULL) {
768 nexpr = stub;
769 stub->is_placeholder = FALSE;
770 go_string_unref (stub->name);
771 stub->name = go_string_new (name);
772 } else {
773 nexpr = expr_name_new (name);
774 nexpr->is_placeholder = (texpr == NULL);
777 parse_pos_init (&nexpr->pos,
778 pp->wb, pp->sheet, pp->eval.col, pp->eval.row);
779 if (texpr == NULL)
780 texpr = gnm_expr_top_new_constant
781 (value_new_error_NAME (NULL));
782 expr_name_set_expr (nexpr, texpr);
783 if (link_to_container)
784 gnm_named_expr_collection_insert (scope, nexpr);
786 return nexpr;
789 void
790 expr_name_ref (GnmNamedExpr *nexpr)
792 g_return_if_fail (nexpr != NULL);
794 nexpr->ref_count++;
797 void
798 expr_name_unref (GnmNamedExpr *nexpr)
800 g_return_if_fail (nexpr != NULL);
802 if (nexpr->ref_count-- > 1)
803 return;
805 if (gnm_debug_flag ("names"))
806 g_printerr ("Finalizing name %s\n", nexpr->name->str);
808 g_return_if_fail (nexpr->scope == NULL);
810 if (nexpr->name) {
811 go_string_unref (nexpr->name);
812 nexpr->name = NULL;
815 if (nexpr->texpr != NULL)
816 expr_name_set_expr (nexpr, NULL);
818 if (nexpr->dependents != NULL) {
819 g_hash_table_destroy (nexpr->dependents);
820 nexpr->dependents = NULL;
823 nexpr->pos.wb = NULL;
824 nexpr->pos.sheet = NULL;
826 g_free (nexpr);
829 GType
830 gnm_named_expr_get_type (void)
832 static GType t = 0;
834 if (t == 0) {
835 t = g_boxed_type_register_static ("GnmNamedExpr",
836 (GBoxedCopyFunc)expr_name_ref,
837 (GBoxedFreeFunc)expr_name_unref);
839 return t;
843 * expr_name_remove :
844 * @nexpr:
846 * Remove a @nexpr from its container and deactivate it.
847 * NOTE : @nexpr may continue to exist if things still have references to it,
848 * but they will evaluate to #REF!
850 void
851 expr_name_remove (GnmNamedExpr *nexpr)
853 g_return_if_fail (nexpr != NULL);
854 g_return_if_fail (nexpr->scope != NULL);
856 if (gnm_debug_flag ("names")) {
857 g_printerr ("Removing name %s from its container%s\n",
858 nexpr->name->str,
859 nexpr->is_placeholder ? " as a placeholder" : "");
862 g_hash_table_remove (
863 nexpr->is_placeholder ? nexpr->scope->placeholders : nexpr->scope->names,
864 nexpr->name);
867 const char *
868 expr_name_name (GnmNamedExpr const *nexpr)
870 g_return_val_if_fail (nexpr != NULL, NULL);
871 return nexpr->name->str;
875 * expr_name_set_name :
876 * @nexpr: the named expression
877 * @new_name: the new name of the expression
879 * returns: TRUE on error.
881 gboolean
882 expr_name_set_name (GnmNamedExpr *nexpr,
883 const char *new_name)
885 const char *old_name;
886 GHashTable *h;
887 GOString fake_new_name;
889 g_return_val_if_fail (nexpr != NULL, TRUE);
890 g_return_val_if_fail (nexpr->scope == NULL || new_name, TRUE);
892 old_name = nexpr->name->str;
893 if (go_str_compare (new_name, old_name) == 0)
894 return FALSE;
896 fake_new_name.str = new_name;
897 #if 0
898 g_printerr ("Renaming %s to %s\n", old_name, new_name);
899 #endif
900 h = nexpr->scope
901 ? (nexpr->is_placeholder
902 ? nexpr->scope->placeholders
903 : nexpr->scope->names)
904 : NULL;
905 if (h) {
906 if (new_name &&
907 (g_hash_table_lookup (nexpr->scope->placeholders,
908 &fake_new_name) ||
909 g_hash_table_lookup (nexpr->scope->names,
910 &fake_new_name))) {
911 /* The only error not to be blamed on the programmer is
912 already-in-use. */
913 return TRUE;
916 g_hash_table_steal (h, nexpr->name);
919 go_string_unref (nexpr->name);
920 nexpr->name = go_string_new (new_name);
922 if (h)
923 g_hash_table_insert (h, (gpointer)nexpr->name, nexpr);
925 return FALSE;
930 * expr_name_as_string :
931 * @nexpr:
932 * @pp: optionally null.
934 * returns a string that the caller needs to free.
936 char *
937 expr_name_as_string (GnmNamedExpr const *nexpr, GnmParsePos const *pp,
938 GnmConventions const *fmt)
940 if (pp == NULL)
941 pp = &nexpr->pos;
942 return gnm_expr_top_as_string (nexpr->texpr, pp, fmt);
945 GnmValue *
946 expr_name_eval (GnmNamedExpr const *nexpr, GnmEvalPos const *pos,
947 GnmExprEvalFlags flags)
949 g_return_val_if_fail (pos, NULL);
951 if (!nexpr)
952 return value_new_error_NAME (pos);
954 return gnm_expr_top_eval (nexpr->texpr, pos, flags);
958 * expr_name_downgrade_to_placeholder:
959 * @nexpr:
961 * Takes a real non-placeholder name and converts it to being a placeholder.
962 * unrefing its expression
964 void
965 expr_name_downgrade_to_placeholder (GnmNamedExpr *nexpr)
967 g_return_if_fail (nexpr != NULL);
969 expr_name_set_is_placeholder (nexpr, TRUE);
970 expr_name_set_expr
971 (nexpr,
972 gnm_expr_top_new_constant (value_new_error_NAME (NULL)));
975 /*******************************************************************
976 * Manage things that depend on named expressions.
979 * expr_name_set_pos:
980 * @nexpr: the named expression
981 * @pp: the new position
983 * Returns a translated error string which the caller must free if something
984 * goes wrong.
986 char *
987 expr_name_set_pos (GnmNamedExpr *nexpr, GnmParsePos const *pp)
989 GnmNamedExprCollection *old_scope, *new_scope;
991 g_return_val_if_fail (nexpr != NULL, NULL);
992 g_return_val_if_fail (pp != NULL, NULL);
994 old_scope = nexpr->scope;
995 new_scope = pp->sheet ? pp->sheet->names : pp->wb->names;
997 if (old_scope != new_scope &&
998 (g_hash_table_lookup (new_scope->placeholders, nexpr->name) ||
999 g_hash_table_lookup (new_scope->names, nexpr->name))) {
1000 const char *fmt = pp->sheet
1001 ? _("'%s' is already defined in sheet")
1002 : _("'%s' is already defined in workbook");
1003 return g_strdup_printf (fmt, nexpr->name);
1006 if (old_scope)
1007 g_hash_table_steal
1008 (nexpr->is_placeholder ? old_scope->placeholders : old_scope->names,
1009 nexpr->name);
1011 nexpr->pos = *pp;
1012 gnm_named_expr_collection_insert (new_scope, nexpr);
1013 return NULL;
1017 * expr_name_set_expr :
1018 * @nexpr: the named expression
1019 * @texpr: the new content
1021 * Unrefs the current content of @nexpr and absorbs a ref to @new_expr.
1023 void
1024 expr_name_set_expr (GnmNamedExpr *nexpr, GnmExprTop const *texpr)
1026 GSList *good = NULL;
1028 g_return_if_fail (nexpr != NULL);
1030 if (texpr == nexpr->texpr)
1031 return;
1032 if (nexpr->texpr != NULL) {
1033 GSList *deps = NULL, *junk = NULL;
1035 deps = expr_name_unlink_deps (nexpr);
1036 expr_name_handle_references (nexpr, FALSE);
1037 gnm_expr_top_unref (nexpr->texpr);
1040 * We do not want to relink deps for sheets that are going
1041 * away. This speeds up exit for workbooks with lots of
1042 * names defined.
1044 while (deps) {
1045 GSList *next = deps->next;
1046 GnmDependent *dep = deps->data;
1048 if (dep->sheet && dep->sheet->being_invalidated)
1049 deps->next = junk, junk = deps;
1050 else
1051 deps->next = good, good = deps;
1053 deps = next;
1056 g_slist_free (junk);
1058 nexpr->texpr = texpr;
1059 dependents_link (good);
1060 g_slist_free (good);
1062 if (texpr != NULL)
1063 expr_name_handle_references (nexpr, TRUE);
1065 expr_name_queue_deps (nexpr);
1068 void
1069 expr_name_add_dep (GnmNamedExpr *nexpr, GnmDependent *dep)
1071 if (nexpr->dependents == NULL)
1072 nexpr->dependents = g_hash_table_new (g_direct_hash,
1073 g_direct_equal);
1075 g_hash_table_insert (nexpr->dependents, dep, dep);
1078 void
1079 expr_name_remove_dep (GnmNamedExpr *nexpr, GnmDependent *dep)
1081 g_return_if_fail (nexpr->dependents != NULL);
1083 g_hash_table_remove (nexpr->dependents, dep);
1087 * expr_name_is_placeholder :
1088 * @ne:
1090 * Returns TRUE if @ne is a placeholder for an unknown name
1092 gboolean
1093 expr_name_is_placeholder (GnmNamedExpr const *nexpr)
1095 g_return_val_if_fail (nexpr != NULL, FALSE);
1097 return (nexpr->texpr &&
1098 gnm_expr_top_is_err (nexpr->texpr, GNM_ERROR_NAME));
1101 void
1102 expr_name_set_is_placeholder (GnmNamedExpr *nexpr, gboolean is_placeholder)
1104 g_return_if_fail (nexpr != NULL);
1106 is_placeholder = !!is_placeholder;
1107 if (nexpr->is_placeholder == is_placeholder)
1108 return;
1109 nexpr->is_placeholder = is_placeholder;
1111 if (nexpr->scope) {
1112 g_hash_table_steal (is_placeholder
1113 ? nexpr->scope->names
1114 : nexpr->scope->placeholders,
1115 nexpr->name);
1116 gnm_named_expr_collection_insert (nexpr->scope, nexpr);
1120 gboolean
1121 expr_name_is_active (GnmNamedExpr const *nexpr)
1123 g_return_val_if_fail (nexpr != NULL, FALSE);
1124 return nexpr->scope != NULL;
1127 struct cb_expr_name_in_use {
1128 GnmNamedExpr *nexpr;
1129 gboolean in_use;
1132 static void
1133 cb_expr_name_in_use (G_GNUC_UNUSED gconstpointer key,
1134 GnmNamedExpr *nexpr,
1135 struct cb_expr_name_in_use *pdata)
1137 if (!pdata->in_use) {
1138 struct cb_name_loop_check args;
1140 args.name = NULL;
1141 args.nexpr = pdata->nexpr;
1142 args.stop_at_name = TRUE;
1143 args.res = FALSE;
1144 gnm_expr_walk (nexpr->texpr->expr, cb_name_loop_check, &args);
1145 pdata->in_use = args.res;
1150 * expr_name_in_use :
1151 * @nexpr: A named expression.
1153 * Returns: TRUE, if the named expression appears to be in use. This is an
1154 * approximation only, as we only look at the workbook in which the name is
1155 * defined.
1158 gboolean
1159 expr_name_in_use (GnmNamedExpr *nexpr)
1161 Workbook *wb;
1162 struct cb_expr_name_in_use data;
1164 if (nexpr->dependents != NULL &&
1165 g_hash_table_size (nexpr->dependents) != 0)
1166 return TRUE;
1168 data.nexpr = nexpr;
1169 data.in_use = FALSE;
1171 wb = nexpr->pos.sheet ? nexpr->pos.sheet->workbook : nexpr->pos.wb;
1172 workbook_foreach_name (wb, FALSE,
1173 (GHFunc)cb_expr_name_in_use,
1174 &data);
1176 return data.in_use;
1181 expr_name_cmp_by_name (GnmNamedExpr const *a, GnmNamedExpr const *b)
1183 Sheet const *sheeta = a->pos.sheet;
1184 Sheet const *sheetb = b->pos.sheet;
1185 int res = 0;
1187 if (sheeta != sheetb) {
1188 /* Locals after non-locals. */
1189 if (!sheeta || !sheetb)
1190 return (!sheeta) - (!sheetb);
1192 /* By non-local sheet order. */
1193 res = g_utf8_collate (sheeta->name_case_insensitive,
1194 sheetb->name_case_insensitive);
1197 if (res == 0) /* By name. */
1198 res = go_utf8_collate_casefold (a->name->str, b->name->str);
1200 return res;
1204 * sheet_names_check :
1205 * @sheet:
1206 * @r:
1208 * Returns a constant string if @sheet!@r is the target of a named range.
1209 * Preference is given to workbook scope over sheet.
1211 char const *
1212 sheet_names_check (Sheet const *sheet, GnmRange const *r)
1214 GnmNamedExpr *nexpr;
1215 GnmRange tmp;
1217 g_return_val_if_fail (IS_SHEET (sheet), NULL);
1218 g_return_val_if_fail (r != NULL, NULL);
1220 tmp = *r;
1221 range_normalize (&tmp);
1222 nexpr = gnm_named_expr_collection_check (sheet->names, sheet, &tmp);
1223 if (nexpr == NULL) {
1224 nexpr = gnm_named_expr_collection_check (sheet->workbook->names, sheet, &tmp);
1225 /* The global name is not accessible if there is a local name (#306685) */
1226 if (nexpr != NULL &&
1227 gnm_named_expr_collection_lookup (sheet->names, nexpr->name->str) != NULL)
1228 return NULL;
1231 return (nexpr != NULL) ? nexpr->name->str : NULL;
1236 * expr_name_perm_add:
1237 * @name: name
1238 * @texpr: string to be the value of the name
1239 * @is_editable: whether this is a predefined action
1241 * This is a wrapper around expr_name_add to set this as permanent name.
1245 void
1246 expr_name_perm_add (Sheet *sheet, char const *name,
1247 GnmExprTop const *value,
1248 gboolean is_editable)
1250 GnmNamedExpr *res;
1251 GnmParsePos pp;
1253 parse_pos_init_sheet (&pp, sheet);
1254 res = expr_name_add (&pp, name, value, NULL, TRUE, NULL);
1255 if (res) {
1256 res->is_permanent = TRUE;
1257 res->is_editable = is_editable;
1261 /* ------------------------------------------------------------------------- */
1263 static void
1264 expr_name_set_expr_ref (GnmNamedExpr *nexpr, GnmExprTop const *texpr)
1266 gnm_expr_top_ref (texpr);
1267 expr_name_set_expr (nexpr, texpr);
1271 * expr_name_set_expr_undo_new:
1272 * @nexpr: #GnmNamedExpr
1274 * Returns: (transfer full):
1276 GOUndo *
1277 expr_name_set_expr_undo_new (GnmNamedExpr *ne)
1279 expr_name_ref (ne);
1280 gnm_expr_top_ref (ne->texpr);
1282 return go_undo_binary_new (ne, (gpointer)ne->texpr,
1283 (GOUndoBinaryFunc)expr_name_set_expr_ref,
1284 (GFreeFunc)expr_name_unref,
1285 (GFreeFunc)gnm_expr_top_unref);
1288 /* ------------------------------------------------------------------------- */