1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * expr-name.c: Supported named expressions
6 * Jody Goldberg <jody@gnome.org>
9 * Michael Meeks <michael@ximian.com>
12 #include <gnumeric-config.h>
13 #include <glib/gi18n-lib.h>
16 #include "expr-name.h"
18 #include "dependent.h"
20 #include "workbook-priv.h"
25 #include "sheet-style.h"
27 #include <goffice/goffice.h>
31 expr_name_validate_r1c1 (const char *name
)
36 if (p
[0] != 'R' && p
[0] != 'r')
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
))
44 if (p
[0] != 'C' && p
[0] != 'c')
47 for (i
= 0; p
[0] && g_ascii_isdigit (p
[0]); p
= g_utf8_next_char (p
))
51 return (p
[0] != '\0');
55 expr_name_validate_a1 (const char *name
)
60 for (i
= 0; *p
&& g_ascii_isalpha(p
[0]);
61 p
= g_utf8_next_char (p
))
63 if (i
==0 || i
>4) /* We want to allow "total2010" and it */
64 /* is unlikely to have more than 456976 */
67 for (i
= 0; *p
&& g_ascii_isdigit (p
[0]);
68 p
= g_utf8_next_char (p
))
77 * @name: tentative name
79 * returns %TRUE if the given name is valid, %FALSE otherwise.
82 expr_name_validate (const char *name
)
87 g_return_val_if_fail (name
!= NULL
, FALSE
);
92 v
= value_new_from_string (VALUE_BOOLEAN
, name
, NULL
, TRUE
);
94 v
= value_new_from_string (VALUE_BOOLEAN
, name
, NULL
, FALSE
);
100 /* Hmm... Now what? */
101 if (!g_unichar_isalpha (g_utf8_get_char (name
)) &&
105 for (p
= name
; *p
; p
= g_utf8_next_char (p
)) {
106 if (!g_unichar_isalnum (g_utf8_get_char (p
)) &&
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
))
118 /* What about R1C1? */
119 if (!expr_name_validate_r1c1 (name
))
127 cb_nexpr_remove (GnmNamedExpr
*nexpr
)
129 g_return_if_fail (nexpr
->scope
!= NULL
);
132 expr_name_set_expr (nexpr
, NULL
);
133 expr_name_unref (nexpr
);
137 cb_collect_name_deps (gpointer key
, G_GNUC_UNUSED gpointer value
,
140 GSList
**list
= user_data
;
141 *list
= g_slist_prepend (*list
, key
);
145 expr_name_unlink_deps (GnmNamedExpr
*nexpr
)
147 GSList
*ptr
, *deps
= NULL
;
149 if (nexpr
->dependents
== NULL
)
152 g_hash_table_foreach (nexpr
->dependents
, cb_collect_name_deps
, &deps
);
155 for (ptr
= deps
; ptr
!= NULL
; ptr
= ptr
->next
) {
156 GnmDependent
*dep
= ptr
->data
;
157 if (dependent_is_linked (dep
))
158 dependent_unlink (dep
);
164 expr_name_relink_deps (GnmNamedExpr
*nexpr
)
168 if (nexpr
->dependents
== NULL
)
171 g_hash_table_foreach (nexpr
->dependents
, cb_collect_name_deps
, &deps
);
172 dependents_link (deps
);
177 fake_go_string_hash (gconstpointer s_
)
179 const GOString
*s
= s_
;
180 return g_str_hash (s
->str
);
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 */
196 /* placeholders for references to undefined names */
197 GHashTable
*placeholders
;
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
);
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
232 * in scope sheet2 we have a name that refers
233 * to sheet1. That will remain!
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
);
245 static GnmNamedExprCollection
*
246 gnm_named_expr_collection_ref (GnmNamedExprCollection
*names
)
253 gnm_named_expr_collection_dump (GnmNamedExprCollection
*names
, const char *id
)
255 g_printerr ("Named collection %s\n", id
);
257 g_printerr (" Empty\n");
261 if (names
->names
&& g_hash_table_size (names
->names
)) {
262 GHashTableIter hiter
;
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",
277 if (names
->placeholders
&& g_hash_table_size (names
->placeholders
)) {
278 GHashTableIter hiter
;
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",
295 gnm_named_expr_collection_sanity_check (GnmNamedExprCollection
*names
,
298 gboolean err
= FALSE
;
299 g_printerr ("Checking sanity for container %s\n", id
);
301 GHashTableIter hiter
;
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
) {
310 g_printerr ("Container %s has strange defined name\n",
312 g_printerr (" key is %p [%s]\n",
314 g_printerr (" target's name is %p [%s]\n",
315 nexpr
->name
, nexpr
->name
->str
);
323 gnm_named_expr_collection_get_type (void)
328 t
= g_boxed_type_register_static ("GnmNamedExprCollection",
329 (GBoxedCopyFunc
)gnm_named_expr_collection_ref
,
330 (GBoxedFreeFunc
)gnm_named_expr_collection_free
);
336 cb_unlink_all_names (G_GNUC_UNUSED gpointer key
,
338 G_GNUC_UNUSED gpointer user_data
)
340 GnmNamedExpr
*nexpr
= value
;
341 GSList
*deps
= expr_name_unlink_deps (nexpr
);
346 gnm_named_expr_collection_unlink (GnmNamedExprCollection
*names
)
351 g_hash_table_foreach (names
->names
,
357 cb_relink_all_names (G_GNUC_UNUSED gpointer key
,
359 G_GNUC_UNUSED gpointer user_data
)
361 GnmNamedExpr
*nexpr
= value
;
362 expr_name_relink_deps (nexpr
);
366 gnm_named_expr_collection_relink (GnmNamedExprCollection
*names
)
371 g_hash_table_foreach (names
->names
,
377 gnm_named_expr_collection_lookup (GnmNamedExprCollection
const *scope
,
384 fake_name
.str
= name
;
385 nexpr
= g_hash_table_lookup (scope
->names
, &fake_name
);
387 nexpr
= g_hash_table_lookup (scope
->placeholders
,
395 cb_list_names (G_GNUC_UNUSED gpointer key
,
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):
410 gnm_named_expr_collection_list (GnmNamedExprCollection
const *scope
)
414 g_hash_table_foreach (scope
->names
,
422 gnm_named_expr_collection_insert (GnmNamedExprCollection
*scope
,
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",
432 nexpr
->is_placeholder
? " as a placeholder" : "");
436 /* name can be active at this point, eg we are converting a
437 * placeholder, or changing a scope */
438 nexpr
->scope
= scope
;
440 (nexpr
->is_placeholder
? scope
->placeholders
: scope
->names
,
441 (gpointer
)nexpr
->name
, nexpr
);
451 cb_check_name (G_GNUC_UNUSED gpointer key
, GnmNamedExpr
*nexpr
,
456 if (nexpr
->scope
== NULL
|| nexpr
->is_hidden
|| !nexpr
->texpr
)
459 v
= gnm_expr_top_get_range (nexpr
->texpr
);
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
)
479 static GnmNamedExpr
*
480 gnm_named_expr_collection_check (GnmNamedExprCollection
*scope
,
481 Sheet
const *sheet
, GnmRange
const *r
)
492 g_hash_table_foreach (scope
->names
, (GHFunc
)cb_check_name
, &user
);
497 * gnm_named_expr_collection_foreach:
498 * @names: #GnmNamedExprCollection
499 * @func: (scope call):
502 * Iterate over all names, including placeholders.
505 gnm_named_expr_collection_foreach (GnmNamedExprCollection
*names
,
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.
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
;
534 /* Implicit reference. */
538 /* No need to do anything during destruction */
539 if (sheet
->deps
== NULL
)
542 found
= g_hash_table_lookup (sheet
->deps
->referencing_names
, nexpr
);
545 g_hash_table_insert (sheet
->deps
->referencing_names
, nexpr
, nexpr
);
547 g_warning ("Name being registered multiple times ?");
551 g_warning ("Unregistered name being removed?");
553 g_hash_table_remove (sheet
->deps
->referencing_names
, nexpr
);
557 g_slist_free (sheets
);
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.
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
);
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
);
594 * Creates a new name without linking it into any container.
597 expr_name_new (char const *name
)
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
);
608 nexpr
->dependents
= NULL
;
609 nexpr
->is_placeholder
= TRUE
;
610 nexpr
->is_hidden
= FALSE
;
611 nexpr
->is_permanent
= FALSE
;
612 nexpr
->is_editable
= TRUE
;
615 if (gnm_debug_flag ("names"))
616 g_printerr ("Created new name %s\n", name
);
621 struct cb_name_loop_check
{
626 gboolean stop_at_name
;
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
);
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
))) {
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
658 * NOTE: if we already have a circular reference beforehand, we will come
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
);
670 args
.stop_at_name
= FALSE
;
672 gnm_expr_walk (texpr
->expr
, cb_name_loop_check
, &args
);
677 expr_name_queue_deps (GnmNamedExpr
*nexpr
)
679 if (nexpr
->dependents
)
680 g_hash_table_foreach (nexpr
->dependents
,
681 (GHFunc
)dependent_queue_recalc
,
689 * @texpr: if texpr == NULL then create a placeholder with value #NAME?
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
701 * 2) if @link_to_container is FALSE the caller DOES OWN a reference, and
702 * can free the result by unrefing the name.
705 expr_name_add (GnmParsePos
const *pp
, char const *name
,
706 GnmExprTop
const *texpr
, char **error_msg
,
707 gboolean link_to_container
,
710 GnmNamedExpr
*nexpr
= NULL
;
711 GnmNamedExprCollection
*scope
= NULL
;
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
) : "-");
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
);
733 *error_msg
= g_strdup_printf (_("'%s' has a circular reference"), name
);
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
);
742 /* there was already a placeholder for this */
743 if (!link_to_container
)
744 expr_name_ref (nexpr
);
748 /* convert the placeholder into a real name */
749 g_hash_table_steal (scope
->placeholders
, &fake_name
);
750 nexpr
->is_placeholder
= FALSE
;
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. */
757 if (nexpr
->is_permanent
)
758 link_to_container
= FALSE
;
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
);
777 stub
->is_placeholder
= FALSE
;
778 go_string_unref (stub
->name
);
779 stub
->name
= go_string_new (name
);
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
);
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
);
798 expr_name_ref (GnmNamedExpr
*nexpr
)
800 g_return_val_if_fail (nexpr
!= NULL
, NULL
);
806 expr_name_unref (GnmNamedExpr
*nexpr
)
808 g_return_if_fail (nexpr
!= NULL
);
810 if (nexpr
->ref_count
-- > 1)
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
);
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
;
836 gnm_named_expr_get_type (void)
841 t
= g_boxed_type_register_static ("GnmNamedExpr",
842 (GBoxedCopyFunc
)expr_name_ref
,
843 (GBoxedFreeFunc
)expr_name_unref
);
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!
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",
865 nexpr
->is_placeholder
? " as a placeholder" : "");
868 g_hash_table_remove (
869 nexpr
->is_placeholder
? nexpr
->scope
->placeholders
: nexpr
->scope
->names
,
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.
888 expr_name_set_name (GnmNamedExpr
*nexpr
,
889 const char *new_name
)
891 const char *old_name
;
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)
902 fake_new_name
.str
= new_name
;
904 g_printerr ("Renaming %s to %s\n", old_name
, new_name
);
907 ? (nexpr
->is_placeholder
908 ? nexpr
->scope
->placeholders
909 : nexpr
->scope
->names
)
913 (g_hash_table_lookup (nexpr
->scope
->placeholders
,
915 g_hash_table_lookup (nexpr
->scope
->names
,
917 /* The only error not to be blamed on the programmer is
922 g_hash_table_steal (h
, nexpr
->name
);
925 go_string_unref (nexpr
->name
);
926 nexpr
->name
= go_string_new (new_name
);
929 g_hash_table_insert (h
, (gpointer
)nexpr
->name
, nexpr
);
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.
944 expr_name_as_string (GnmNamedExpr
const *nexpr
, GnmParsePos
const *pp
,
945 GnmConventions
const *fmt
)
949 return gnm_expr_top_as_string (nexpr
->texpr
, pp
, fmt
);
954 * @nexpr: A #GnmNamedExpr
955 * @pos: Position where evaluation takes place
956 * @flags: #GnmExprEvalFlags flags describing context.
958 * Returns: (transfer full): The resulting value.
961 expr_name_eval (GnmNamedExpr
const *nexpr
, GnmEvalPos
const *pos
,
962 GnmExprEvalFlags flags
)
964 g_return_val_if_fail (pos
, NULL
);
967 return value_new_error_NAME (pos
);
969 return gnm_expr_top_eval (nexpr
->texpr
, pos
, flags
);
973 * expr_name_downgrade_to_placeholder:
976 * Takes a real non-placeholder name and converts it to being a placeholder.
977 * unrefing its expression
980 expr_name_downgrade_to_placeholder (GnmNamedExpr
*nexpr
)
982 g_return_if_fail (nexpr
!= NULL
);
984 expr_name_set_is_placeholder (nexpr
, TRUE
);
987 gnm_expr_top_new_constant (value_new_error_NAME (NULL
)));
990 /*******************************************************************
991 * Manage things that depend on named expressions.
995 * @nexpr: the named expression
996 * @pp: the new position
998 * Returns a translated error string which the caller must free if something
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
);
1023 (nexpr
->is_placeholder
? old_scope
->placeholders
: old_scope
->names
,
1027 gnm_named_expr_collection_insert (new_scope
, nexpr
);
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.
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
)
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
1060 GSList
*next
= deps
->next
;
1061 GnmDependent
*dep
= deps
->data
;
1063 if (dep
->sheet
&& dep
->sheet
->being_invalidated
)
1064 deps
->next
= junk
, junk
= deps
;
1066 deps
->next
= good
, good
= deps
;
1071 g_slist_free (junk
);
1073 nexpr
->texpr
= texpr
;
1074 dependents_link (good
);
1075 g_slist_free (good
);
1078 expr_name_handle_references (nexpr
, TRUE
);
1080 expr_name_queue_deps (nexpr
);
1084 expr_name_add_dep (GnmNamedExpr
*nexpr
, GnmDependent
*dep
)
1086 if (nexpr
->dependents
== NULL
)
1087 nexpr
->dependents
= g_hash_table_new (g_direct_hash
,
1090 g_hash_table_insert (nexpr
->dependents
, dep
, dep
);
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:
1105 * Returns TRUE if @ne is a placeholder for an unknown name
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
));
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
)
1124 nexpr
->is_placeholder
= is_placeholder
;
1127 g_hash_table_steal (is_placeholder
1128 ? nexpr
->scope
->names
1129 : nexpr
->scope
->placeholders
,
1131 gnm_named_expr_collection_insert (nexpr
->scope
, nexpr
);
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
;
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
;
1156 args
.nexpr
= pdata
->nexpr
;
1157 args
.stop_at_name
= TRUE
;
1159 gnm_expr_walk (nexpr
->texpr
->expr
, cb_name_loop_check
, &args
);
1160 pdata
->in_use
= args
.res
;
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
1174 expr_name_in_use (GnmNamedExpr
*nexpr
)
1177 struct cb_expr_name_in_use data
;
1179 if (nexpr
->dependents
!= NULL
&&
1180 g_hash_table_size (nexpr
->dependents
) != 0)
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
,
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
;
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
);
1219 * sheet_names_check:
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.
1229 sheet_names_check (Sheet
const *sheet
, GnmRange
const *r
)
1231 GnmNamedExpr
*nexpr
;
1234 g_return_val_if_fail (IS_SHEET (sheet
), NULL
);
1235 g_return_val_if_fail (r
!= NULL
, NULL
);
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
)
1248 return (nexpr
!= NULL
) ? nexpr
->name
->str
: NULL
;
1253 * expr_name_perm_add:
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.
1263 expr_name_perm_add (Sheet
*sheet
, char const *name
,
1264 GnmExprTop
const *value
,
1265 gboolean is_editable
)
1270 parse_pos_init_sheet (&pp
, sheet
);
1271 res
= expr_name_add (&pp
, name
, value
, NULL
, TRUE
, NULL
);
1273 res
->is_permanent
= TRUE
;
1274 res
->is_editable
= is_editable
;
1278 /* ------------------------------------------------------------------------- */
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):
1294 expr_name_set_expr_undo_new (GnmNamedExpr
*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 /* ------------------------------------------------------------------------- */