Update Spanish translation
[gnumeric.git] / src / expr-name.c
blobd9a138dbd52564ff918a654234a4eae3f8a94d43
1 /*
2 * expr-name.c: Supported named expressions
4 * Author:
5 * Jody Goldberg <jody@gnome.org>
7 * Based on work by:
8 * Michael Meeks <michael@ximian.com>
9 */
11 #include <gnumeric-config.h>
12 #include <glib/gi18n-lib.h>
13 #include <string.h>
14 #include <gnumeric.h>
15 #include <expr-name.h>
17 #include <dependent.h>
18 #include <value.h>
19 #include <workbook-priv.h>
20 #include <expr.h>
21 #include <sheet.h>
22 #include <ranges.h>
23 #include <gutils.h>
24 #include <sheet-style.h>
26 #include <goffice/goffice.h>
29 static gboolean
30 expr_name_validate_r1c1 (const char *name)
32 const char *p = name;
33 gint i;
35 if (p[0] != 'R' && p[0] != 'r')
36 return TRUE;
37 p++;
38 /* no need to worry about [] since they are not alphanumeric */
39 for (i = 0; p[0] && g_ascii_isdigit (p[0]); p = g_utf8_next_char (p))
40 i++;
41 if (i==0)
42 return TRUE;
43 if (p[0] != 'C' && p[0] != 'c')
44 return TRUE;
45 p++;
46 for (i = 0; p[0] && g_ascii_isdigit (p[0]); p = g_utf8_next_char (p))
47 i++;
48 if (i==0)
49 return TRUE;
50 return (p[0] != '\0');
53 static gboolean
54 expr_name_validate_a1 (const char *name)
56 const char *p = name;
57 gint i;
59 for (i = 0; *p && g_ascii_isalpha(p[0]);
60 p = g_utf8_next_char (p))
61 i++;
62 if (i==0 || i>4) /* We want to allow "total2010" and it */
63 /* is unlikely to have more than 456976 */
64 /* columns atm */
65 return TRUE;
66 for (i = 0; *p && g_ascii_isdigit (p[0]);
67 p = g_utf8_next_char (p))
68 i++;
69 if (i==0)
70 return TRUE;
71 return (*p != '\0');
74 /**
75 * expr_name_validate:
76 * @name: tentative name
78 * returns %TRUE if the given name is valid, %FALSE otherwise.
80 gboolean
81 expr_name_validate (const char *name)
83 const char *p;
84 GnmValue *v;
86 g_return_val_if_fail (name != NULL, FALSE);
88 if (name[0] == 0)
89 return FALSE;
91 v = value_new_from_string (VALUE_BOOLEAN, name, NULL, TRUE);
92 if (!v)
93 v = value_new_from_string (VALUE_BOOLEAN, name, NULL, FALSE);
94 if (v) {
95 value_release (v);
96 return FALSE;
99 /* Hmm... Now what? */
100 if (!g_unichar_isalpha (g_utf8_get_char (name)) &&
101 name[0] != '_')
102 return FALSE;
104 for (p = name; *p; p = g_utf8_next_char (p)) {
105 if (!g_unichar_isalnum (g_utf8_get_char (p)) &&
106 p[0] != '_')
107 return FALSE;
110 /* Make sure it's not A1 etc.*/
111 /* Note that we can't use our regular parsers */
112 /* since we also have to avoid names that may become */
113 /* sensible when the sheet size changes. */
114 if (!expr_name_validate_a1 (name))
115 return FALSE;
117 /* What about R1C1? */
118 if (!expr_name_validate_r1c1 (name))
119 return FALSE;
121 return TRUE;
125 static void
126 cb_nexpr_remove (GnmNamedExpr *nexpr)
128 g_return_if_fail (nexpr->scope != NULL);
130 nexpr->scope = NULL;
131 expr_name_set_expr (nexpr, NULL);
132 expr_name_unref (nexpr);
135 static void
136 cb_collect_name_deps (gpointer key, G_GNUC_UNUSED gpointer value,
137 gpointer user_data)
139 GSList **list = user_data;
140 *list = g_slist_prepend (*list, key);
143 static GSList *
144 expr_name_unlink_deps (GnmNamedExpr *nexpr)
146 GSList *ptr, *deps = NULL;
148 if (nexpr->dependents == NULL)
149 return NULL;
151 g_hash_table_foreach (nexpr->dependents, cb_collect_name_deps, &deps);
153 /* pull them out */
154 for (ptr = deps ; ptr != NULL ; ptr = ptr->next) {
155 GnmDependent *dep = ptr->data;
156 if (dependent_is_linked (dep))
157 dependent_unlink (dep);
159 return deps;
162 static void
163 expr_name_relink_deps (GnmNamedExpr *nexpr)
165 GSList *deps = NULL;
167 if (nexpr->dependents == NULL)
168 return;
170 g_hash_table_foreach (nexpr->dependents, cb_collect_name_deps, &deps);
171 dependents_link (deps);
172 g_slist_free (deps);
175 static guint
176 fake_go_string_hash (gconstpointer s_)
178 const GOString *s = s_;
179 return g_str_hash (s->str);
182 static gboolean
183 fake_go_string_equal (gconstpointer a_, gconstpointer b_)
185 const GOString *a = a_;
186 const GOString *b = b_;
187 return g_str_equal (a->str, b->str);
191 struct _GnmNamedExprCollection {
192 /* all the defined names */
193 GHashTable *names;
195 /* placeholders for references to undefined names */
196 GHashTable *placeholders;
198 /* <private> */
199 unsigned ref_count; /* boxed type */
203 * gnm_named_expr_collection_new:
205 * Returns: (transfer full): the newly allocated #GnmNamedExprCollection.
207 GnmNamedExprCollection *
208 gnm_named_expr_collection_new (void)
210 GnmNamedExprCollection *res = g_new (GnmNamedExprCollection, 1);
212 res->names = g_hash_table_new_full
213 (fake_go_string_hash, fake_go_string_equal,
214 NULL, (GDestroyNotify) cb_nexpr_remove);
215 res->placeholders = g_hash_table_new_full
216 (fake_go_string_hash, fake_go_string_equal,
217 NULL, (GDestroyNotify) cb_nexpr_remove);
218 res->ref_count = 1;
220 return res;
224 * gnm_named_expr_collection_free:
225 * @names: The collection of names
227 * Frees names defined in the local scope.
228 * NOTE : THIS DOES NOT INVALIDATE NAMES THAT REFER
229 * TO THIS SCOPE.
230 * eg
231 * in scope sheet2 we have a name that refers
232 * to sheet1. That will remain!
234 void
235 gnm_named_expr_collection_free (GnmNamedExprCollection *names)
237 if (names != NULL && names->ref_count-- < 2) {
238 g_hash_table_destroy (names->names);
239 g_hash_table_destroy (names->placeholders);
240 g_free (names);
244 static GnmNamedExprCollection *
245 gnm_named_expr_collection_ref (GnmNamedExprCollection *names)
247 names->ref_count++;
248 return names;
251 void
252 gnm_named_expr_collection_dump (GnmNamedExprCollection *names, const char *id)
254 g_printerr ("Named collection %s\n", id);
255 if (!names) {
256 g_printerr (" Empty\n");
257 return;
260 if (names->names && g_hash_table_size (names->names)) {
261 GHashTableIter hiter;
262 gpointer key, value;
264 g_printerr (" Defined names:\n");
265 g_hash_table_iter_init (&hiter, names->names);
266 while (g_hash_table_iter_next (&hiter, &key, &value)) {
267 const GOString *name = key;
268 GnmNamedExpr const *nexpr = value;
269 g_printerr (" [%s] =>\n", name->str);
270 if (name != nexpr->name)
271 g_printerr (" Weird keys: %p vs %p\n",
272 name, nexpr->name);
276 if (names->placeholders && g_hash_table_size (names->placeholders)) {
277 GHashTableIter hiter;
278 gpointer key, value;
280 g_printerr (" Defined placeholders:\n");
281 g_hash_table_iter_init (&hiter, names->placeholders);
282 while (g_hash_table_iter_next (&hiter, &key, &value)) {
283 const GOString *name = key;
284 GnmNamedExpr const *nexpr = value;
285 g_printerr (" [%s] =>\n", name->str);
286 if (name != nexpr->name)
287 g_printerr (" Weird keys: %p vs %p\n",
288 name, nexpr->name);
293 gboolean
294 gnm_named_expr_collection_sanity_check (GnmNamedExprCollection *names,
295 const char *id)
297 gboolean err = FALSE;
298 g_printerr ("Checking sanity for container %s\n", id);
299 if (names->names) {
300 GHashTableIter hiter;
301 gpointer key, value;
303 g_hash_table_iter_init (&hiter, names->names);
304 while (g_hash_table_iter_next (&hiter, &key, &value)) {
305 const GOString *name = key;
306 GnmNamedExpr const *nexpr = value;
307 if (name != nexpr->name) {
308 err = TRUE;
309 g_printerr ("Container %s has strange defined name\n",
310 id);
311 g_printerr (" key is %p [%s]\n",
312 name, name->str);
313 g_printerr (" target's name is %p [%s]\n",
314 nexpr->name, nexpr->name->str);
318 return err;
321 GType
322 gnm_named_expr_collection_get_type (void)
324 static GType t = 0;
326 if (t == 0) {
327 t = g_boxed_type_register_static ("GnmNamedExprCollection",
328 (GBoxedCopyFunc)gnm_named_expr_collection_ref,
329 (GBoxedFreeFunc)gnm_named_expr_collection_free);
331 return t;
334 static void
335 cb_unlink_all_names (G_GNUC_UNUSED gpointer key,
336 gpointer value,
337 G_GNUC_UNUSED gpointer user_data)
339 GnmNamedExpr *nexpr = value;
340 GSList *deps = expr_name_unlink_deps (nexpr);
341 g_slist_free (deps);
344 void
345 gnm_named_expr_collection_unlink (GnmNamedExprCollection *names)
347 if (!names)
348 return;
350 g_hash_table_foreach (names->names,
351 cb_unlink_all_names,
352 NULL);
355 static void
356 cb_relink_all_names (G_GNUC_UNUSED gpointer key,
357 gpointer value,
358 G_GNUC_UNUSED gpointer user_data)
360 GnmNamedExpr *nexpr = value;
361 expr_name_relink_deps (nexpr);
364 void
365 gnm_named_expr_collection_relink (GnmNamedExprCollection *names)
367 if (!names)
368 return;
370 g_hash_table_foreach (names->names,
371 cb_relink_all_names,
372 NULL);
375 GnmNamedExpr *
376 gnm_named_expr_collection_lookup (GnmNamedExprCollection const *scope,
377 char const *name)
379 if (scope != NULL) {
380 GOString fake_name;
381 GnmNamedExpr *nexpr;
383 fake_name.str = name;
384 nexpr = g_hash_table_lookup (scope->names, &fake_name);
385 if (nexpr == NULL)
386 nexpr = g_hash_table_lookup (scope->placeholders,
387 &fake_name);
388 return nexpr;
389 } else
390 return NULL;
393 static void
394 cb_list_names (G_GNUC_UNUSED gpointer key,
395 gpointer value,
396 gpointer user_data)
398 GSList **pres = user_data;
399 GO_SLIST_PREPEND (*pres, value);
403 * gnm_named_expr_collection_list:
404 * @scope: #GnmNamedExprCollection
406 * Returns: (element-type GnmNamedExpr) (transfer container):
408 GSList *
409 gnm_named_expr_collection_list (GnmNamedExprCollection const *scope)
411 GSList *res = NULL;
412 if (scope) {
413 g_hash_table_foreach (scope->names,
414 cb_list_names,
415 &res);
417 return res;
420 static void
421 gnm_named_expr_collection_insert (GnmNamedExprCollection *scope,
422 GnmNamedExpr *nexpr)
424 if (gnm_debug_flag ("names")) {
425 char *scope_name = nexpr->pos.sheet
426 ? g_strdup_printf ("sheet %s", nexpr->pos.sheet->name_quoted)
427 : g_strdup ("workbook");
428 g_printerr ("Inserting name %s into its %s container%s\n",
429 nexpr->name->str,
430 scope_name,
431 nexpr->is_placeholder ? " as a placeholder" : "");
432 g_free (scope_name);
435 /* name can be active at this point, eg we are converting a
436 * placeholder, or changing a scope */
437 nexpr->scope = scope;
438 g_hash_table_replace
439 (nexpr->is_placeholder ? scope->placeholders : scope->names,
440 (gpointer)nexpr->name, nexpr);
443 typedef struct {
444 Sheet const *sheet;
445 GnmRange const *r;
446 GnmNamedExpr *res;
447 } CheckName;
449 static void
450 cb_check_name (G_GNUC_UNUSED gpointer key, GnmNamedExpr *nexpr,
451 CheckName *user)
453 GnmValue *v;
455 if (nexpr->scope == NULL || nexpr->is_hidden || !nexpr->texpr)
456 return;
458 v = gnm_expr_top_get_range (nexpr->texpr);
459 if (v != NULL) {
460 if (VALUE_IS_CELLRANGE (v)) {
461 GnmRangeRef const *ref = &v->v_range.cell;
462 if (!ref->a.col_relative &&
463 !ref->b.col_relative &&
464 !ref->a.row_relative &&
465 !ref->b.row_relative &&
466 eval_sheet (ref->a.sheet, user->sheet) == user->sheet &&
467 eval_sheet (ref->b.sheet, user->sheet) == user->sheet &&
468 MIN (ref->a.col, ref->b.col) == user->r->start.col &&
469 MAX (ref->a.col, ref->b.col) == user->r->end.col &&
470 MIN (ref->a.row, ref->b.row) == user->r->start.row &&
471 MAX (ref->a.row, ref->b.row) == user->r->end.row)
472 user->res = nexpr;
474 value_release (v);
478 static GnmNamedExpr *
479 gnm_named_expr_collection_check (GnmNamedExprCollection *scope,
480 Sheet const *sheet, GnmRange const *r)
482 CheckName user;
484 if (scope == NULL)
485 return NULL;
487 user.sheet = sheet;
488 user.r = r;
489 user.res = NULL;
491 g_hash_table_foreach (scope->names, (GHFunc)cb_check_name, &user);
492 return user.res;
496 * gnm_named_expr_collection_foreach:
497 * @names: #GnmNamedExprCollection
498 * @func: (scope call):
499 * @data: user data.
501 * Iterate over all names, including placeholders.
503 void
504 gnm_named_expr_collection_foreach (GnmNamedExprCollection *names,
505 GHFunc func,
506 gpointer data)
508 g_hash_table_foreach (names->names, func, data);
509 g_hash_table_foreach (names->placeholders, func, data);
512 /******************************************************************************/
515 * expr_name_handle_references:
517 * Register or unregister a name with
518 * all of the sheets it explicitly references. This is necessary
519 * because names are not dependents, and if they reference a deleted
520 * sheet we will not notice.
522 static void
523 expr_name_handle_references (GnmNamedExpr *nexpr, gboolean add)
525 GSList *sheets, *ptr;
527 sheets = gnm_expr_top_referenced_sheets (nexpr->texpr);
529 for (ptr = sheets ; ptr != NULL ; ptr = ptr->next) {
530 Sheet *sheet = ptr->data;
531 GnmNamedExpr *found;
533 /* Implicit reference. */
534 if (!sheet)
535 continue;
537 /* No need to do anything during destruction */
538 if (sheet->deps == NULL)
539 continue;
541 found = g_hash_table_lookup (sheet->deps->referencing_names, nexpr);
542 if (add) {
543 if (found == NULL) {
544 g_hash_table_insert (sheet->deps->referencing_names, nexpr, nexpr);
545 } else {
546 g_warning ("Name being registered multiple times ?");
548 } else {
549 if (found == NULL) {
550 g_warning ("Unregistered name being removed?");
551 } else {
552 g_hash_table_remove (sheet->deps->referencing_names, nexpr);
556 g_slist_free (sheets);
561 * expr_name_lookup:
562 * @pos: #GnmParsePos identifying a #Sheet or a #Workbook.
563 * @name: name of #GnmNamedExpr to look up.
565 * Return: (transfer none) (nullable): #GnmNamedExpr named @name in the scope
566 * given by @pos; %NULL if no such #GnmNamedExpr exists.
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 * expr_name_check_for_loop:
651 * @name: tentative name
652 * @texpr: tentative expression
654 * Returns: %TRUE if defining the tentative name would cause a circular
655 * name reference.
657 * NOTE: if we already have a circular reference beforehand, we will come
658 * to serious grief.
660 gboolean
661 expr_name_check_for_loop (char const *name, GnmExprTop const *texpr)
663 struct cb_name_loop_check args;
665 g_return_val_if_fail (texpr != NULL, TRUE);
667 args.name = name;
668 args.nexpr = NULL;
669 args.stop_at_name = FALSE;
670 args.res = FALSE;
671 gnm_expr_walk (texpr->expr, cb_name_loop_check, &args);
672 return args.res;
675 static void
676 expr_name_queue_deps (GnmNamedExpr *nexpr)
678 if (nexpr->dependents)
679 g_hash_table_foreach (nexpr->dependents,
680 (GHFunc)dependent_queue_recalc,
681 NULL);
685 * expr_name_add: (skip)
686 * @pp:
687 * @name:
688 * @texpr: if texpr == NULL then create a placeholder with value #NAME?
689 * @error_msg: (out) (optional) (nullable):
690 * @link_to_container:
692 * Absorbs the reference to @texpr.
693 * If @error_msg is non NULL it may hold a pointer to a translated descriptive
694 * string. NOTE : caller is responsible for freeing the error message.
696 * The reference semantics of the new expression are
697 * 1) new names with @link_to_container TRUE are referenced by the container.
698 * The caller DOES NOT OWN a reference to the result, and needs to add their
699 * own.
700 * 2) if @link_to_container is %FALSE the caller DOES OWN a reference, and
701 * can free the result by unrefing the name.
703 GnmNamedExpr *
704 expr_name_add (GnmParsePos const *pp, char const *name,
705 GnmExprTop const *texpr, char **error_msg,
706 gboolean link_to_container,
707 GnmNamedExpr *stub)
709 GnmNamedExpr *nexpr = NULL;
710 GnmNamedExprCollection *scope = NULL;
711 GOString fake_name;
713 g_return_val_if_fail (pp != NULL, NULL);
714 g_return_val_if_fail (pp->sheet != NULL || pp->wb != NULL, NULL);
715 g_return_val_if_fail (name != NULL, NULL);
716 g_return_val_if_fail (stub == NULL || stub->is_placeholder, NULL);
718 if (error_msg)
719 *error_msg = NULL;
721 fake_name.str = name;
723 if (gnm_debug_flag ("names")) {
724 char *str = gnm_expr_top_as_string (texpr, pp, NULL);
725 g_printerr ("Adding Name=[%s] texpr=[%s] stub=[%s]\n",
726 name, str, stub ? expr_name_name (stub) : "-");
727 g_free (str);
730 if (texpr != NULL &&
731 (expr_name_check_for_loop (name, texpr) ||
732 (stub && expr_name_check_for_loop (expr_name_name (stub), texpr)))) {
733 gnm_expr_top_unref (texpr);
734 if (error_msg)
735 *error_msg = g_strdup_printf (_("'%s' has a circular reference"), name);
736 return NULL;
739 scope = (pp->sheet != NULL) ? pp->sheet->names : pp->wb->names;
740 /* see if there was a place holder */
741 nexpr = g_hash_table_lookup (scope->placeholders, &fake_name);
742 if (nexpr != NULL) {
743 if (texpr == NULL) {
744 /* there was already a placeholder for this */
745 if (!link_to_container)
746 expr_name_ref (nexpr);
747 return nexpr;
750 /* convert the placeholder into a real name */
751 g_hash_table_steal (scope->placeholders, &fake_name);
752 nexpr->is_placeholder = FALSE;
753 } else {
754 nexpr = g_hash_table_lookup (scope->names, &fake_name);
755 /* If this is a permanent name, we may be adding it */
756 /* on opening of a file, although */
757 /* the name is already in place. */
758 if (nexpr != NULL) {
759 if (nexpr->is_permanent)
760 link_to_container = FALSE;
761 else {
762 if (error_msg != NULL)
763 *error_msg = (pp->sheet != NULL)
764 ? g_strdup_printf (_("'%s' is already defined in sheet"), name)
765 : g_strdup_printf (_("'%s' is already defined in workbook"), name);
767 gnm_expr_top_unref (texpr);
768 return NULL;
773 if (nexpr == NULL) {
774 if (stub != NULL) {
775 nexpr = stub;
776 stub->is_placeholder = FALSE;
777 go_string_unref (stub->name);
778 stub->name = go_string_new (name);
779 } else {
780 nexpr = expr_name_new (name);
781 nexpr->is_placeholder = (texpr == NULL);
784 parse_pos_init (&nexpr->pos,
785 pp->wb, pp->sheet, pp->eval.col, pp->eval.row);
786 if (texpr == NULL)
787 texpr = gnm_expr_top_new_constant
788 (value_new_error_NAME (NULL));
789 expr_name_set_expr (nexpr, texpr);
790 if (link_to_container)
791 gnm_named_expr_collection_insert (scope, nexpr);
793 return nexpr;
796 GnmNamedExpr *
797 expr_name_ref (GnmNamedExpr *nexpr)
799 g_return_val_if_fail (nexpr != NULL, NULL);
800 nexpr->ref_count++;
801 return nexpr;
804 void
805 expr_name_unref (GnmNamedExpr *nexpr)
807 g_return_if_fail (nexpr != NULL);
809 if (nexpr->ref_count-- > 1)
810 return;
812 if (gnm_debug_flag ("names"))
813 g_printerr ("Finalizing name %s\n", nexpr->name->str);
815 g_return_if_fail (nexpr->scope == NULL);
817 go_string_unref (nexpr->name);
818 nexpr->name = NULL;
820 if (nexpr->texpr != NULL)
821 expr_name_set_expr (nexpr, NULL);
823 if (nexpr->dependents != NULL) {
824 g_hash_table_destroy (nexpr->dependents);
825 nexpr->dependents = NULL;
828 nexpr->pos.wb = NULL;
829 nexpr->pos.sheet = NULL;
831 g_free (nexpr);
834 GType
835 gnm_named_expr_get_type (void)
837 static GType t = 0;
839 if (t == 0) {
840 t = g_boxed_type_register_static ("GnmNamedExpr",
841 (GBoxedCopyFunc)expr_name_ref,
842 (GBoxedFreeFunc)expr_name_unref);
844 return t;
848 * expr_name_remove:
849 * @nexpr:
851 * Remove a @nexpr from its container and deactivate it.
852 * NOTE : @nexpr may continue to exist if things still have references to it,
853 * but they will evaluate to #REF!
855 void
856 expr_name_remove (GnmNamedExpr *nexpr)
858 g_return_if_fail (nexpr != NULL);
859 g_return_if_fail (nexpr->scope != NULL);
861 if (gnm_debug_flag ("names")) {
862 g_printerr ("Removing name %s from its container%s\n",
863 nexpr->name->str,
864 nexpr->is_placeholder ? " as a placeholder" : "");
867 g_hash_table_remove (
868 nexpr->is_placeholder ? nexpr->scope->placeholders : nexpr->scope->names,
869 nexpr->name);
872 const char *
873 expr_name_name (GnmNamedExpr const *nexpr)
875 g_return_val_if_fail (nexpr != NULL, NULL);
876 return nexpr->name->str;
880 * expr_name_set_name:
881 * @nexpr: the named expression
882 * @new_name: the new name of the expression
884 * returns: TRUE on error.
886 gboolean
887 expr_name_set_name (GnmNamedExpr *nexpr,
888 const char *new_name)
890 const char *old_name;
891 GHashTable *h;
892 GOString fake_new_name;
894 g_return_val_if_fail (nexpr != NULL, TRUE);
895 g_return_val_if_fail (nexpr->scope == NULL || new_name, TRUE);
897 old_name = nexpr->name->str;
898 if (go_str_compare (new_name, old_name) == 0)
899 return FALSE;
901 fake_new_name.str = new_name;
902 #if 0
903 g_printerr ("Renaming %s to %s\n", old_name, new_name);
904 #endif
905 h = nexpr->scope
906 ? (nexpr->is_placeholder
907 ? nexpr->scope->placeholders
908 : nexpr->scope->names)
909 : NULL;
910 if (h) {
911 if (new_name &&
912 (g_hash_table_lookup (nexpr->scope->placeholders,
913 &fake_new_name) ||
914 g_hash_table_lookup (nexpr->scope->names,
915 &fake_new_name))) {
916 /* The only error not to be blamed on the programmer is
917 already-in-use. */
918 return TRUE;
921 g_hash_table_steal (h, nexpr->name);
924 go_string_unref (nexpr->name);
925 nexpr->name = go_string_new (new_name);
927 if (h)
928 g_hash_table_insert (h, (gpointer)nexpr->name, nexpr);
930 return FALSE;
935 * expr_name_as_string:
936 * @nexpr: A #GnmNamedExpr
937 * @pp: (nullable): Position where name was defined.
938 * @fmt: #GnmConventions describing how to render @nexpr
940 * Returns: (transfer full): The rendering of @nexpr given convention @fmt.
942 char *
943 expr_name_as_string (GnmNamedExpr const *nexpr, GnmParsePos const *pp,
944 GnmConventions const *fmt)
946 if (pp == NULL)
947 pp = &nexpr->pos;
948 return gnm_expr_top_as_string (nexpr->texpr, pp, fmt);
952 * expr_name_eval:
953 * @nexpr: A #GnmNamedExpr
954 * @pos: Position where evaluation takes place
955 * @flags: #GnmExprEvalFlags flags describing context.
957 * Returns: (transfer full): The resulting value.
959 GnmValue *
960 expr_name_eval (GnmNamedExpr const *nexpr, GnmEvalPos const *pos,
961 GnmExprEvalFlags flags)
963 g_return_val_if_fail (pos, NULL);
965 if (!nexpr)
966 return value_new_error_NAME (pos);
968 return gnm_expr_top_eval (nexpr->texpr, pos, flags);
972 * expr_name_downgrade_to_placeholder:
973 * @nexpr:
975 * Takes a real non-placeholder name and converts it to being a placeholder.
976 * unrefing its expression
978 void
979 expr_name_downgrade_to_placeholder (GnmNamedExpr *nexpr)
981 g_return_if_fail (nexpr != NULL);
983 expr_name_set_is_placeholder (nexpr, TRUE);
984 expr_name_set_expr
985 (nexpr,
986 gnm_expr_top_new_constant (value_new_error_NAME (NULL)));
989 /*******************************************************************
990 * Manage things that depend on named expressions.
993 * expr_name_set_pos:
994 * @nexpr: the named expression
995 * @pp: the new position
997 * Returns a translated error string which the caller must free if something
998 * goes wrong.
1000 char *
1001 expr_name_set_pos (GnmNamedExpr *nexpr, GnmParsePos const *pp)
1003 GnmNamedExprCollection *old_scope, *new_scope;
1005 g_return_val_if_fail (nexpr != NULL, NULL);
1006 g_return_val_if_fail (pp != NULL, NULL);
1008 old_scope = nexpr->scope;
1009 new_scope = pp->sheet ? pp->sheet->names : pp->wb->names;
1011 if (old_scope != new_scope &&
1012 (g_hash_table_lookup (new_scope->placeholders, nexpr->name) ||
1013 g_hash_table_lookup (new_scope->names, nexpr->name))) {
1014 const char *fmt = pp->sheet
1015 ? _("'%s' is already defined in sheet")
1016 : _("'%s' is already defined in workbook");
1017 return g_strdup_printf (fmt, nexpr->name);
1020 if (old_scope)
1021 g_hash_table_steal
1022 (nexpr->is_placeholder ? old_scope->placeholders : old_scope->names,
1023 nexpr->name);
1025 nexpr->pos = *pp;
1026 gnm_named_expr_collection_insert (new_scope, nexpr);
1027 return NULL;
1031 * expr_name_set_expr:
1032 * @nexpr: #GnmNamedExpr to change
1033 * @texpr: (transfer full) (nullable): the new contents
1035 * Set the content of @nexpr to @texpr.
1037 void
1038 expr_name_set_expr (GnmNamedExpr *nexpr, GnmExprTop const *texpr)
1040 GSList *good = NULL;
1042 g_return_if_fail (nexpr != NULL);
1044 if (texpr == nexpr->texpr)
1045 return;
1046 if (nexpr->texpr != NULL) {
1047 GSList *deps = NULL, *junk = NULL;
1049 deps = expr_name_unlink_deps (nexpr);
1050 expr_name_handle_references (nexpr, FALSE);
1051 gnm_expr_top_unref (nexpr->texpr);
1054 * We do not want to relink deps for sheets that are going
1055 * away. This speeds up exit for workbooks with lots of
1056 * names defined.
1058 while (deps) {
1059 GSList *next = deps->next;
1060 GnmDependent *dep = deps->data;
1062 if (dep->sheet && dep->sheet->being_invalidated)
1063 deps->next = junk, junk = deps;
1064 else
1065 deps->next = good, good = deps;
1067 deps = next;
1070 g_slist_free (junk);
1072 nexpr->texpr = texpr;
1073 dependents_link (good);
1074 g_slist_free (good);
1076 if (texpr != NULL)
1077 expr_name_handle_references (nexpr, TRUE);
1079 expr_name_queue_deps (nexpr);
1082 void
1083 expr_name_add_dep (GnmNamedExpr *nexpr, GnmDependent *dep)
1085 if (nexpr->dependents == NULL)
1086 nexpr->dependents = g_hash_table_new (g_direct_hash,
1087 g_direct_equal);
1089 g_hash_table_insert (nexpr->dependents, dep, dep);
1092 void
1093 expr_name_remove_dep (GnmNamedExpr *nexpr, GnmDependent *dep)
1095 g_return_if_fail (nexpr->dependents != NULL);
1097 g_hash_table_remove (nexpr->dependents, dep);
1101 * expr_name_is_placeholder:
1102 * @ne:
1104 * Returns: %TRUE if @ne is a placeholder for an unknown name
1106 gboolean
1107 expr_name_is_placeholder (GnmNamedExpr const *nexpr)
1109 g_return_val_if_fail (nexpr != NULL, FALSE);
1111 return (nexpr->texpr &&
1112 gnm_expr_top_is_err (nexpr->texpr, GNM_ERROR_NAME));
1115 void
1116 expr_name_set_is_placeholder (GnmNamedExpr *nexpr, gboolean is_placeholder)
1118 g_return_if_fail (nexpr != NULL);
1120 is_placeholder = !!is_placeholder;
1121 if (nexpr->is_placeholder == is_placeholder)
1122 return;
1123 nexpr->is_placeholder = is_placeholder;
1125 if (nexpr->scope) {
1126 g_hash_table_steal (is_placeholder
1127 ? nexpr->scope->names
1128 : nexpr->scope->placeholders,
1129 nexpr->name);
1130 gnm_named_expr_collection_insert (nexpr->scope, nexpr);
1134 gboolean
1135 expr_name_is_active (GnmNamedExpr const *nexpr)
1137 g_return_val_if_fail (nexpr != NULL, FALSE);
1138 return nexpr->scope != NULL;
1141 struct cb_expr_name_in_use {
1142 GnmNamedExpr *nexpr;
1143 gboolean in_use;
1146 static void
1147 cb_expr_name_in_use (G_GNUC_UNUSED gconstpointer key,
1148 GnmNamedExpr *nexpr,
1149 struct cb_expr_name_in_use *pdata)
1151 if (!pdata->in_use) {
1152 struct cb_name_loop_check args;
1154 args.name = NULL;
1155 args.nexpr = pdata->nexpr;
1156 args.stop_at_name = TRUE;
1157 args.res = FALSE;
1158 gnm_expr_walk (nexpr->texpr->expr, cb_name_loop_check, &args);
1159 pdata->in_use = args.res;
1164 * expr_name_in_use:
1165 * @nexpr: A named expression.
1167 * Returns: TRUE, if the named expression appears to be in use. This is an
1168 * approximation only, as we only look at the workbook in which the name is
1169 * defined.
1172 gboolean
1173 expr_name_in_use (GnmNamedExpr *nexpr)
1175 Workbook *wb;
1176 struct cb_expr_name_in_use data;
1178 if (nexpr->dependents != NULL &&
1179 g_hash_table_size (nexpr->dependents) != 0)
1180 return TRUE;
1182 data.nexpr = nexpr;
1183 data.in_use = FALSE;
1185 wb = nexpr->pos.sheet ? nexpr->pos.sheet->workbook : nexpr->pos.wb;
1186 workbook_foreach_name (wb, FALSE,
1187 (GHFunc)cb_expr_name_in_use,
1188 &data);
1190 return data.in_use;
1195 expr_name_cmp_by_name (GnmNamedExpr const *a, GnmNamedExpr const *b)
1197 Sheet const *sheeta = a->pos.sheet;
1198 Sheet const *sheetb = b->pos.sheet;
1199 int res = 0;
1201 if (sheeta != sheetb) {
1202 /* Locals after non-locals. */
1203 if (!sheeta || !sheetb)
1204 return (!sheeta) - (!sheetb);
1206 /* By non-local sheet order. */
1207 res = g_utf8_collate (sheeta->name_case_insensitive,
1208 sheetb->name_case_insensitive);
1211 if (res == 0) /* By name. */
1212 res = go_utf8_collate_casefold (a->name->str, b->name->str);
1214 return res;
1218 * sheet_names_check:
1219 * @sheet: #Sheet
1220 * @r: #GnmRange
1222 * Returns: (transfer none) (nullable): The name of a #GnmNamedExpr if
1223 * @sheet!@r is the target of a named range.
1225 * Preference is given to workbook scope over sheet.
1227 char const *
1228 sheet_names_check (Sheet const *sheet, GnmRange const *r)
1230 GnmNamedExpr *nexpr;
1231 GnmRange tmp;
1233 g_return_val_if_fail (IS_SHEET (sheet), NULL);
1234 g_return_val_if_fail (r != NULL, NULL);
1236 tmp = *r;
1237 range_normalize (&tmp);
1238 nexpr = gnm_named_expr_collection_check (sheet->names, sheet, &tmp);
1239 if (nexpr == NULL) {
1240 nexpr = gnm_named_expr_collection_check (sheet->workbook->names, sheet, &tmp);
1241 /* The global name is not accessible if there is a local name (#306685) */
1242 if (nexpr != NULL &&
1243 gnm_named_expr_collection_lookup (sheet->names, nexpr->name->str) != NULL)
1244 return NULL;
1247 return (nexpr != NULL) ? nexpr->name->str : NULL;
1252 * expr_name_perm_add:
1253 * @name: name
1254 * @texpr: string to be the value of the name
1255 * @is_editable: whether this is a predefined action
1257 * This is a wrapper around expr_name_add to set this as permanent name.
1261 void
1262 expr_name_perm_add (Sheet *sheet, char const *name,
1263 GnmExprTop const *value,
1264 gboolean is_editable)
1266 GnmNamedExpr *res;
1267 GnmParsePos pp;
1269 parse_pos_init_sheet (&pp, sheet);
1270 res = expr_name_add (&pp, name, value, NULL, TRUE, NULL);
1271 if (res) {
1272 res->is_permanent = TRUE;
1273 res->is_editable = is_editable;
1277 /* ------------------------------------------------------------------------- */
1279 static void
1280 expr_name_set_expr_ref (GnmNamedExpr *nexpr, GnmExprTop const *texpr)
1282 gnm_expr_top_ref (texpr);
1283 expr_name_set_expr (nexpr, texpr);
1287 * expr_name_set_expr_undo_new:
1288 * @nexpr: #GnmNamedExpr
1290 * Returns: (transfer full):
1292 GOUndo *
1293 expr_name_set_expr_undo_new (GnmNamedExpr *ne)
1295 expr_name_ref (ne);
1296 gnm_expr_top_ref (ne->texpr);
1298 return go_undo_binary_new (ne, (gpointer)ne->texpr,
1299 (GOUndoBinaryFunc)expr_name_set_expr_ref,
1300 (GFreeFunc)expr_name_unref,
1301 (GFreeFunc)gnm_expr_top_unref);
1304 /* ------------------------------------------------------------------------- */