GUI: Move .ui files from goffice resources to glib resources
[gnumeric.git] / src / expr-name.c
blobbec07af69b13a451771e967837159aaf32de2253
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: #GnmParsePos identifying a #Sheet or a #Workbook.
564 * @name: name of #GnmNamedExpr to look up.
566 * Return: (transfer none) (nullable): #GnmNamedExpr named @name in the scope
567 * given by @pos; %NULL if no such #GnmNamedExpr exists.
569 GnmNamedExpr *
570 expr_name_lookup (GnmParsePos const *pp, char const *name)
572 GnmNamedExpr *res = NULL;
573 Sheet const *sheet = NULL;
574 Workbook const *wb = NULL;
576 g_return_val_if_fail (name != NULL, NULL);
578 if (pp != NULL) {
579 sheet = pp->sheet;
580 wb = (sheet != NULL) ? sheet->workbook : pp->wb;
583 if (sheet != NULL && sheet->names != NULL)
584 res = gnm_named_expr_collection_lookup (sheet->names, name);
585 if (res == NULL && wb != NULL && wb->names != NULL)
586 res = gnm_named_expr_collection_lookup (wb->names, name);
587 return res;
591 * expr_name_new:
592 * @name:
594 * Creates a new name without linking it into any container.
596 GnmNamedExpr *
597 expr_name_new (char const *name)
599 GnmNamedExpr *nexpr;
601 g_return_val_if_fail (name != NULL, NULL);
603 nexpr = g_new0 (GnmNamedExpr,1);
605 nexpr->ref_count = 1;
606 nexpr->name = go_string_new (name);
607 nexpr->texpr = NULL;
608 nexpr->dependents = NULL;
609 nexpr->is_placeholder = TRUE;
610 nexpr->is_hidden = FALSE;
611 nexpr->is_permanent = FALSE;
612 nexpr->is_editable = TRUE;
613 nexpr->scope = NULL;
615 if (gnm_debug_flag ("names"))
616 g_printerr ("Created new name %s\n", name);
618 return nexpr;
621 struct cb_name_loop_check {
622 /* One of these */
623 char const *name;
624 GnmNamedExpr *nexpr;
626 gboolean stop_at_name;
627 gboolean res;
630 static GnmExpr const *
631 cb_name_loop_check (GnmExpr const *expr, GnmExprWalk *data)
633 struct cb_name_loop_check *args = data->user;
635 GnmNamedExpr const *nexpr2 = gnm_expr_get_name (expr);
636 if (nexpr2) {
637 if ((args->name && !strcmp (nexpr2->name->str, args->name)) ||
638 args->nexpr == nexpr2 ||
639 (!args->stop_at_name && nexpr2->texpr &&
640 /* Is the following right? It drops args->nexpr */
641 expr_name_check_for_loop (args->name, nexpr2->texpr))) {
642 args->res = TRUE;
643 data->stop = TRUE;
647 return NULL;
651 * expr_name_check_for_loop:
652 * @name: tentative name
653 * @texpr: tentative expression
655 * Returns: %TRUE if defining the tentative name would cause a circular
656 * name reference.
658 * NOTE: if we already have a circular reference beforehand, we will come
659 * to serious grief.
661 gboolean
662 expr_name_check_for_loop (char const *name, GnmExprTop const *texpr)
664 struct cb_name_loop_check args;
666 g_return_val_if_fail (texpr != NULL, TRUE);
668 args.name = name;
669 args.nexpr = NULL;
670 args.stop_at_name = FALSE;
671 args.res = FALSE;
672 gnm_expr_walk (texpr->expr, cb_name_loop_check, &args);
673 return args.res;
676 static void
677 expr_name_queue_deps (GnmNamedExpr *nexpr)
679 if (nexpr->dependents)
680 g_hash_table_foreach (nexpr->dependents,
681 (GHFunc)dependent_queue_recalc,
682 NULL);
686 * expr_name_add:
687 * @pp:
688 * @name:
689 * @texpr: if texpr == NULL then create a placeholder with value #NAME?
690 * @error_msg:
691 * @link_to_container:
693 * Absorbs the reference to @texpr.
694 * If @error_msg is non NULL it may hold a pointer to a translated descriptive
695 * string. NOTE : caller is responsible for freeing the error message.
697 * The reference semantics of the new expression are
698 * 1) new names with @link_to_container TRUE are referenced by the container.
699 * The caller DOES NOT OWN a reference to the result, and needs to add their
700 * own.
701 * 2) if @link_to_container is FALSE the caller DOES OWN a reference, and
702 * can free the result by unrefing the name.
704 GnmNamedExpr *
705 expr_name_add (GnmParsePos const *pp, char const *name,
706 GnmExprTop const *texpr, char **error_msg,
707 gboolean link_to_container,
708 GnmNamedExpr *stub)
710 GnmNamedExpr *nexpr = NULL;
711 GnmNamedExprCollection *scope = NULL;
712 GOString fake_name;
714 g_return_val_if_fail (pp != NULL, NULL);
715 g_return_val_if_fail (pp->sheet != NULL || pp->wb != NULL, NULL);
716 g_return_val_if_fail (name != NULL, NULL);
717 g_return_val_if_fail (stub == NULL || stub->is_placeholder, NULL);
719 fake_name.str = name;
721 if (gnm_debug_flag ("names")) {
722 char *str = gnm_expr_top_as_string (texpr, pp, NULL);
723 g_printerr ("Adding Name=[%s] texpr=[%s] stub=[%s]\n",
724 name, str, stub ? expr_name_name (stub) : "-");
725 g_free (str);
728 if (texpr != NULL &&
729 (expr_name_check_for_loop (name, texpr) ||
730 (stub && expr_name_check_for_loop (expr_name_name (stub), texpr)))) {
731 gnm_expr_top_unref (texpr);
732 if (error_msg)
733 *error_msg = g_strdup_printf (_("'%s' has a circular reference"), name);
734 return NULL;
737 scope = (pp->sheet != NULL) ? pp->sheet->names : pp->wb->names;
738 /* see if there was a place holder */
739 nexpr = g_hash_table_lookup (scope->placeholders, &fake_name);
740 if (nexpr != NULL) {
741 if (texpr == NULL) {
742 /* there was already a placeholder for this */
743 if (!link_to_container)
744 expr_name_ref (nexpr);
745 return nexpr;
748 /* convert the placeholder into a real name */
749 g_hash_table_steal (scope->placeholders, &fake_name);
750 nexpr->is_placeholder = FALSE;
751 } else {
752 nexpr = g_hash_table_lookup (scope->names, &fake_name);
753 /* If this is a permanent name, we may be adding it */
754 /* on opening of a file, although */
755 /* the name is already in place. */
756 if (nexpr != NULL) {
757 if (nexpr->is_permanent)
758 link_to_container = FALSE;
759 else {
760 if (error_msg != NULL)
761 *error_msg = (pp->sheet != NULL)
762 ? g_strdup_printf (_("'%s' is already defined in sheet"), name)
763 : g_strdup_printf (_("'%s' is already defined in workbook"), name);
765 gnm_expr_top_unref (texpr);
766 return NULL;
771 if (error_msg)
772 *error_msg = NULL;
774 if (nexpr == NULL) {
775 if (stub != NULL) {
776 nexpr = stub;
777 stub->is_placeholder = FALSE;
778 go_string_unref (stub->name);
779 stub->name = go_string_new (name);
780 } else {
781 nexpr = expr_name_new (name);
782 nexpr->is_placeholder = (texpr == NULL);
785 parse_pos_init (&nexpr->pos,
786 pp->wb, pp->sheet, pp->eval.col, pp->eval.row);
787 if (texpr == NULL)
788 texpr = gnm_expr_top_new_constant
789 (value_new_error_NAME (NULL));
790 expr_name_set_expr (nexpr, texpr);
791 if (link_to_container)
792 gnm_named_expr_collection_insert (scope, nexpr);
794 return nexpr;
797 GnmNamedExpr *
798 expr_name_ref (GnmNamedExpr *nexpr)
800 g_return_val_if_fail (nexpr != NULL, NULL);
801 nexpr->ref_count++;
802 return nexpr;
805 void
806 expr_name_unref (GnmNamedExpr *nexpr)
808 g_return_if_fail (nexpr != NULL);
810 if (nexpr->ref_count-- > 1)
811 return;
813 if (gnm_debug_flag ("names"))
814 g_printerr ("Finalizing name %s\n", nexpr->name->str);
816 g_return_if_fail (nexpr->scope == NULL);
818 go_string_unref (nexpr->name);
819 nexpr->name = NULL;
821 if (nexpr->texpr != NULL)
822 expr_name_set_expr (nexpr, NULL);
824 if (nexpr->dependents != NULL) {
825 g_hash_table_destroy (nexpr->dependents);
826 nexpr->dependents = NULL;
829 nexpr->pos.wb = NULL;
830 nexpr->pos.sheet = NULL;
832 g_free (nexpr);
835 GType
836 gnm_named_expr_get_type (void)
838 static GType t = 0;
840 if (t == 0) {
841 t = g_boxed_type_register_static ("GnmNamedExpr",
842 (GBoxedCopyFunc)expr_name_ref,
843 (GBoxedFreeFunc)expr_name_unref);
845 return t;
849 * expr_name_remove:
850 * @nexpr:
852 * Remove a @nexpr from its container and deactivate it.
853 * NOTE : @nexpr may continue to exist if things still have references to it,
854 * but they will evaluate to #REF!
856 void
857 expr_name_remove (GnmNamedExpr *nexpr)
859 g_return_if_fail (nexpr != NULL);
860 g_return_if_fail (nexpr->scope != NULL);
862 if (gnm_debug_flag ("names")) {
863 g_printerr ("Removing name %s from its container%s\n",
864 nexpr->name->str,
865 nexpr->is_placeholder ? " as a placeholder" : "");
868 g_hash_table_remove (
869 nexpr->is_placeholder ? nexpr->scope->placeholders : nexpr->scope->names,
870 nexpr->name);
873 const char *
874 expr_name_name (GnmNamedExpr const *nexpr)
876 g_return_val_if_fail (nexpr != NULL, NULL);
877 return nexpr->name->str;
881 * expr_name_set_name:
882 * @nexpr: the named expression
883 * @new_name: the new name of the expression
885 * returns: TRUE on error.
887 gboolean
888 expr_name_set_name (GnmNamedExpr *nexpr,
889 const char *new_name)
891 const char *old_name;
892 GHashTable *h;
893 GOString fake_new_name;
895 g_return_val_if_fail (nexpr != NULL, TRUE);
896 g_return_val_if_fail (nexpr->scope == NULL || new_name, TRUE);
898 old_name = nexpr->name->str;
899 if (go_str_compare (new_name, old_name) == 0)
900 return FALSE;
902 fake_new_name.str = new_name;
903 #if 0
904 g_printerr ("Renaming %s to %s\n", old_name, new_name);
905 #endif
906 h = nexpr->scope
907 ? (nexpr->is_placeholder
908 ? nexpr->scope->placeholders
909 : nexpr->scope->names)
910 : NULL;
911 if (h) {
912 if (new_name &&
913 (g_hash_table_lookup (nexpr->scope->placeholders,
914 &fake_new_name) ||
915 g_hash_table_lookup (nexpr->scope->names,
916 &fake_new_name))) {
917 /* The only error not to be blamed on the programmer is
918 already-in-use. */
919 return TRUE;
922 g_hash_table_steal (h, nexpr->name);
925 go_string_unref (nexpr->name);
926 nexpr->name = go_string_new (new_name);
928 if (h)
929 g_hash_table_insert (h, (gpointer)nexpr->name, nexpr);
931 return FALSE;
936 * expr_name_as_string:
937 * @nexpr: A #GnmNamedExpr
938 * @pp: (nullable): Position where name was defined.
939 * @fmt: #GnmConventions describing how to render @nexpr
941 * Returns: (transfer full): The rendering of @nexpr given convention @fmt.
943 char *
944 expr_name_as_string (GnmNamedExpr const *nexpr, GnmParsePos const *pp,
945 GnmConventions const *fmt)
947 if (pp == NULL)
948 pp = &nexpr->pos;
949 return gnm_expr_top_as_string (nexpr->texpr, pp, fmt);
953 * expr_name_eval:
954 * @nexpr: A #GnmNamedExpr
955 * @pos: Position where evaluation takes place
956 * @flags: #GnmExprEvalFlags flags describing context.
958 * Returns: (transfer full): The resulting value.
960 GnmValue *
961 expr_name_eval (GnmNamedExpr const *nexpr, GnmEvalPos const *pos,
962 GnmExprEvalFlags flags)
964 g_return_val_if_fail (pos, NULL);
966 if (!nexpr)
967 return value_new_error_NAME (pos);
969 return gnm_expr_top_eval (nexpr->texpr, pos, flags);
973 * expr_name_downgrade_to_placeholder:
974 * @nexpr:
976 * Takes a real non-placeholder name and converts it to being a placeholder.
977 * unrefing its expression
979 void
980 expr_name_downgrade_to_placeholder (GnmNamedExpr *nexpr)
982 g_return_if_fail (nexpr != NULL);
984 expr_name_set_is_placeholder (nexpr, TRUE);
985 expr_name_set_expr
986 (nexpr,
987 gnm_expr_top_new_constant (value_new_error_NAME (NULL)));
990 /*******************************************************************
991 * Manage things that depend on named expressions.
994 * expr_name_set_pos:
995 * @nexpr: the named expression
996 * @pp: the new position
998 * Returns a translated error string which the caller must free if something
999 * goes wrong.
1001 char *
1002 expr_name_set_pos (GnmNamedExpr *nexpr, GnmParsePos const *pp)
1004 GnmNamedExprCollection *old_scope, *new_scope;
1006 g_return_val_if_fail (nexpr != NULL, NULL);
1007 g_return_val_if_fail (pp != NULL, NULL);
1009 old_scope = nexpr->scope;
1010 new_scope = pp->sheet ? pp->sheet->names : pp->wb->names;
1012 if (old_scope != new_scope &&
1013 (g_hash_table_lookup (new_scope->placeholders, nexpr->name) ||
1014 g_hash_table_lookup (new_scope->names, nexpr->name))) {
1015 const char *fmt = pp->sheet
1016 ? _("'%s' is already defined in sheet")
1017 : _("'%s' is already defined in workbook");
1018 return g_strdup_printf (fmt, nexpr->name);
1021 if (old_scope)
1022 g_hash_table_steal
1023 (nexpr->is_placeholder ? old_scope->placeholders : old_scope->names,
1024 nexpr->name);
1026 nexpr->pos = *pp;
1027 gnm_named_expr_collection_insert (new_scope, nexpr);
1028 return NULL;
1032 * expr_name_set_expr:
1033 * @nexpr: #GnmNamedExpr to change
1034 * @texpr: (transfer full) (nullable): the new contents
1036 * Set the content of @nexpr to @texpr.
1038 void
1039 expr_name_set_expr (GnmNamedExpr *nexpr, GnmExprTop const *texpr)
1041 GSList *good = NULL;
1043 g_return_if_fail (nexpr != NULL);
1045 if (texpr == nexpr->texpr)
1046 return;
1047 if (nexpr->texpr != NULL) {
1048 GSList *deps = NULL, *junk = NULL;
1050 deps = expr_name_unlink_deps (nexpr);
1051 expr_name_handle_references (nexpr, FALSE);
1052 gnm_expr_top_unref (nexpr->texpr);
1055 * We do not want to relink deps for sheets that are going
1056 * away. This speeds up exit for workbooks with lots of
1057 * names defined.
1059 while (deps) {
1060 GSList *next = deps->next;
1061 GnmDependent *dep = deps->data;
1063 if (dep->sheet && dep->sheet->being_invalidated)
1064 deps->next = junk, junk = deps;
1065 else
1066 deps->next = good, good = deps;
1068 deps = next;
1071 g_slist_free (junk);
1073 nexpr->texpr = texpr;
1074 dependents_link (good);
1075 g_slist_free (good);
1077 if (texpr != NULL)
1078 expr_name_handle_references (nexpr, TRUE);
1080 expr_name_queue_deps (nexpr);
1083 void
1084 expr_name_add_dep (GnmNamedExpr *nexpr, GnmDependent *dep)
1086 if (nexpr->dependents == NULL)
1087 nexpr->dependents = g_hash_table_new (g_direct_hash,
1088 g_direct_equal);
1090 g_hash_table_insert (nexpr->dependents, dep, dep);
1093 void
1094 expr_name_remove_dep (GnmNamedExpr *nexpr, GnmDependent *dep)
1096 g_return_if_fail (nexpr->dependents != NULL);
1098 g_hash_table_remove (nexpr->dependents, dep);
1102 * expr_name_is_placeholder:
1103 * @ne:
1105 * Returns TRUE if @ne is a placeholder for an unknown name
1107 gboolean
1108 expr_name_is_placeholder (GnmNamedExpr const *nexpr)
1110 g_return_val_if_fail (nexpr != NULL, FALSE);
1112 return (nexpr->texpr &&
1113 gnm_expr_top_is_err (nexpr->texpr, GNM_ERROR_NAME));
1116 void
1117 expr_name_set_is_placeholder (GnmNamedExpr *nexpr, gboolean is_placeholder)
1119 g_return_if_fail (nexpr != NULL);
1121 is_placeholder = !!is_placeholder;
1122 if (nexpr->is_placeholder == is_placeholder)
1123 return;
1124 nexpr->is_placeholder = is_placeholder;
1126 if (nexpr->scope) {
1127 g_hash_table_steal (is_placeholder
1128 ? nexpr->scope->names
1129 : nexpr->scope->placeholders,
1130 nexpr->name);
1131 gnm_named_expr_collection_insert (nexpr->scope, nexpr);
1135 gboolean
1136 expr_name_is_active (GnmNamedExpr const *nexpr)
1138 g_return_val_if_fail (nexpr != NULL, FALSE);
1139 return nexpr->scope != NULL;
1142 struct cb_expr_name_in_use {
1143 GnmNamedExpr *nexpr;
1144 gboolean in_use;
1147 static void
1148 cb_expr_name_in_use (G_GNUC_UNUSED gconstpointer key,
1149 GnmNamedExpr *nexpr,
1150 struct cb_expr_name_in_use *pdata)
1152 if (!pdata->in_use) {
1153 struct cb_name_loop_check args;
1155 args.name = NULL;
1156 args.nexpr = pdata->nexpr;
1157 args.stop_at_name = TRUE;
1158 args.res = FALSE;
1159 gnm_expr_walk (nexpr->texpr->expr, cb_name_loop_check, &args);
1160 pdata->in_use = args.res;
1165 * expr_name_in_use:
1166 * @nexpr: A named expression.
1168 * Returns: TRUE, if the named expression appears to be in use. This is an
1169 * approximation only, as we only look at the workbook in which the name is
1170 * defined.
1173 gboolean
1174 expr_name_in_use (GnmNamedExpr *nexpr)
1176 Workbook *wb;
1177 struct cb_expr_name_in_use data;
1179 if (nexpr->dependents != NULL &&
1180 g_hash_table_size (nexpr->dependents) != 0)
1181 return TRUE;
1183 data.nexpr = nexpr;
1184 data.in_use = FALSE;
1186 wb = nexpr->pos.sheet ? nexpr->pos.sheet->workbook : nexpr->pos.wb;
1187 workbook_foreach_name (wb, FALSE,
1188 (GHFunc)cb_expr_name_in_use,
1189 &data);
1191 return data.in_use;
1196 expr_name_cmp_by_name (GnmNamedExpr const *a, GnmNamedExpr const *b)
1198 Sheet const *sheeta = a->pos.sheet;
1199 Sheet const *sheetb = b->pos.sheet;
1200 int res = 0;
1202 if (sheeta != sheetb) {
1203 /* Locals after non-locals. */
1204 if (!sheeta || !sheetb)
1205 return (!sheeta) - (!sheetb);
1207 /* By non-local sheet order. */
1208 res = g_utf8_collate (sheeta->name_case_insensitive,
1209 sheetb->name_case_insensitive);
1212 if (res == 0) /* By name. */
1213 res = go_utf8_collate_casefold (a->name->str, b->name->str);
1215 return res;
1219 * sheet_names_check:
1220 * @sheet: #Sheet
1221 * @r: #GnmRange
1223 * Returns: (transfer none) (nullable): The name of a #GnmNamedExpr if
1224 * @sheet!@r is the target of a named range.
1226 * Preference is given to workbook scope over sheet.
1228 char const *
1229 sheet_names_check (Sheet const *sheet, GnmRange const *r)
1231 GnmNamedExpr *nexpr;
1232 GnmRange tmp;
1234 g_return_val_if_fail (IS_SHEET (sheet), NULL);
1235 g_return_val_if_fail (r != NULL, NULL);
1237 tmp = *r;
1238 range_normalize (&tmp);
1239 nexpr = gnm_named_expr_collection_check (sheet->names, sheet, &tmp);
1240 if (nexpr == NULL) {
1241 nexpr = gnm_named_expr_collection_check (sheet->workbook->names, sheet, &tmp);
1242 /* The global name is not accessible if there is a local name (#306685) */
1243 if (nexpr != NULL &&
1244 gnm_named_expr_collection_lookup (sheet->names, nexpr->name->str) != NULL)
1245 return NULL;
1248 return (nexpr != NULL) ? nexpr->name->str : NULL;
1253 * expr_name_perm_add:
1254 * @name: name
1255 * @texpr: string to be the value of the name
1256 * @is_editable: whether this is a predefined action
1258 * This is a wrapper around expr_name_add to set this as permanent name.
1262 void
1263 expr_name_perm_add (Sheet *sheet, char const *name,
1264 GnmExprTop const *value,
1265 gboolean is_editable)
1267 GnmNamedExpr *res;
1268 GnmParsePos pp;
1270 parse_pos_init_sheet (&pp, sheet);
1271 res = expr_name_add (&pp, name, value, NULL, TRUE, NULL);
1272 if (res) {
1273 res->is_permanent = TRUE;
1274 res->is_editable = is_editable;
1278 /* ------------------------------------------------------------------------- */
1280 static void
1281 expr_name_set_expr_ref (GnmNamedExpr *nexpr, GnmExprTop const *texpr)
1283 gnm_expr_top_ref (texpr);
1284 expr_name_set_expr (nexpr, texpr);
1288 * expr_name_set_expr_undo_new:
1289 * @nexpr: #GnmNamedExpr
1291 * Returns: (transfer full):
1293 GOUndo *
1294 expr_name_set_expr_undo_new (GnmNamedExpr *ne)
1296 expr_name_ref (ne);
1297 gnm_expr_top_ref (ne->texpr);
1299 return go_undo_binary_new (ne, (gpointer)ne->texpr,
1300 (GOUndoBinaryFunc)expr_name_set_expr_ref,
1301 (GFreeFunc)expr_name_unref,
1302 (GFreeFunc)gnm_expr_top_unref);
1305 /* ------------------------------------------------------------------------- */