1 /*
2  * expr-name.c: Supported named expressions
3  *
4  * Author:
5  *    Jody Goldberg <jody@gnome.org>
6  *
7  * Based on work by:
8  *    Michael Meeks <michael@ximian.com>
9  */
10 
11 #include <gnumeric-config.h>
12 #include <glib/gi18n-lib.h>
13 #include <string.h>
14 #include <gnumeric.h>
15 #include <expr-name.h>
16 
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>
25 
26 #include <goffice/goffice.h>
27 
28 
29 static gboolean
expr_name_validate_r1c1(const char * name)30 expr_name_validate_r1c1 (const char *name)
31 {
32 	const char *p = name;
33 	gint i;
34 
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');
51 }
52 
53 static gboolean
expr_name_validate_a1(const char * name)54 expr_name_validate_a1 (const char *name)
55 {
56 	const char *p = name;
57 	gint i;
58 
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');
72 }
73 
74 /**
75  * expr_name_validate:
76  * @name: tentative name
77  *
78  * returns %TRUE if the given name is valid, %FALSE otherwise.
79  */
80 gboolean
expr_name_validate(const char * name)81 expr_name_validate (const char *name)
82 {
83 	const char *p;
84 	GnmValue *v;
85 
86 	g_return_val_if_fail (name != NULL, FALSE);
87 
88 	if (name[0] == 0)
89 		return FALSE;
90 
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;
97 	}
98 
99 	/* Hmm...   Now what?  */
100 	if (!g_unichar_isalpha (g_utf8_get_char (name)) &&
101 	    name[0] != '_')
102 		return FALSE;
103 
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;
108 	}
109 
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;
116 
117 	/* What about R1C1?  */
118 	if (!expr_name_validate_r1c1 (name))
119 		return FALSE;
120 
121 	return TRUE;
122 }
123 
124 
125 static void
cb_nexpr_remove(GnmNamedExpr * nexpr)126 cb_nexpr_remove (GnmNamedExpr *nexpr)
127 {
128 	g_return_if_fail (nexpr->scope != NULL);
129 
130 	nexpr->scope = NULL;
131 	expr_name_set_expr (nexpr, NULL);
132 	expr_name_unref (nexpr);
133 }
134 
135 static void
cb_collect_name_deps(gpointer key,G_GNUC_UNUSED gpointer value,gpointer user_data)136 cb_collect_name_deps (gpointer key, G_GNUC_UNUSED gpointer value,
137 		      gpointer user_data)
138 {
139 	GSList **list = user_data;
140 	*list = g_slist_prepend (*list, key);
141 }
142 
143 static GSList *
expr_name_unlink_deps(GnmNamedExpr * nexpr)144 expr_name_unlink_deps (GnmNamedExpr *nexpr)
145 {
146 	GSList *ptr, *deps = NULL;
147 
148 	if (nexpr->dependents == NULL)
149 		return NULL;
150 
151 	g_hash_table_foreach (nexpr->dependents, cb_collect_name_deps, &deps);
152 
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);
158 	}
159 	return deps;
160 }
161 
162 static void
expr_name_relink_deps(GnmNamedExpr * nexpr)163 expr_name_relink_deps (GnmNamedExpr *nexpr)
164 {
165 	GSList *deps = NULL;
166 
167 	if (nexpr->dependents == NULL)
168 		return;
169 
170 	g_hash_table_foreach (nexpr->dependents, cb_collect_name_deps, &deps);
171 	dependents_link (deps);
172 	g_slist_free (deps);
173 }
174 
175 static guint
fake_go_string_hash(gconstpointer s_)176 fake_go_string_hash (gconstpointer s_)
177 {
178 	const GOString *s = s_;
179 	return g_str_hash (s->str);
180 }
181 
182 static gboolean
fake_go_string_equal(gconstpointer a_,gconstpointer b_)183 fake_go_string_equal (gconstpointer a_, gconstpointer b_)
184 {
185 	const GOString *a = a_;
186 	const GOString *b = b_;
187 	return g_str_equal (a->str, b->str);
188 }
189 
190 
191 struct _GnmNamedExprCollection {
192 	/* all the defined names */
193 	GHashTable *names;
194 
195 	/* placeholders for references to undefined names */
196 	GHashTable *placeholders;
197 
198 	/* <private> */
199 	unsigned ref_count;     /* boxed type */
200 };
201 
202 /**
203  * gnm_named_expr_collection_new:
204  *
205  * Returns: (transfer full): the newly allocated #GnmNamedExprCollection.
206  **/
207 GnmNamedExprCollection *
gnm_named_expr_collection_new(void)208 gnm_named_expr_collection_new (void)
209 {
210 	GnmNamedExprCollection *res = g_new (GnmNamedExprCollection, 1);
211 
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;
219 
220 	return res;
221 }
222 
223 /**
224  * gnm_named_expr_collection_unref:
225  * @names: The collection of names
226  *
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!
233  **/
234 void
gnm_named_expr_collection_unref(GnmNamedExprCollection * names)235 gnm_named_expr_collection_unref (GnmNamedExprCollection *names)
236 {
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);
241 	}
242 }
243 
244 static GnmNamedExprCollection *
gnm_named_expr_collection_ref(GnmNamedExprCollection * names)245 gnm_named_expr_collection_ref (GnmNamedExprCollection *names)
246 {
247 	names->ref_count++;
248 	return names;
249 }
250 
251 void
gnm_named_expr_collection_dump(GnmNamedExprCollection * names,const char * id)252 gnm_named_expr_collection_dump (GnmNamedExprCollection *names, const char *id)
253 {
254 	g_printerr ("Named collection %s\n", id);
255 	if (!names) {
256 		g_printerr ("  Empty\n");
257 		return;
258 	}
259 
260 	if (names->names && g_hash_table_size (names->names)) {
261 		GHashTableIter hiter;
262 		gpointer key, value;
263 
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);
273 		}
274 	}
275 
276 	if (names->placeholders && g_hash_table_size (names->placeholders)) {
277 		GHashTableIter hiter;
278 		gpointer key, value;
279 
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);
289 		}
290 	}
291 }
292 
293 gboolean
gnm_named_expr_collection_sanity_check(GnmNamedExprCollection * names,const char * id)294 gnm_named_expr_collection_sanity_check (GnmNamedExprCollection *names,
295 					const char *id)
296 {
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;
302 
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);
315 			}
316 		}
317 	}
318 	return err;
319 }
320 
321 GType
gnm_named_expr_collection_get_type(void)322 gnm_named_expr_collection_get_type (void)
323 {
324 	static GType t = 0;
325 
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_unref);
330 	}
331 	return t;
332 }
333 
334 static void
cb_unlink_all_names(G_GNUC_UNUSED gpointer key,gpointer value,G_GNUC_UNUSED gpointer user_data)335 cb_unlink_all_names (G_GNUC_UNUSED gpointer key,
336 		     gpointer value,
337 		     G_GNUC_UNUSED gpointer user_data)
338 {
339 	GnmNamedExpr *nexpr = value;
340 	GSList *deps = expr_name_unlink_deps (nexpr);
341 	g_slist_free (deps);
342 }
343 
344 void
gnm_named_expr_collection_unlink(GnmNamedExprCollection * names)345 gnm_named_expr_collection_unlink (GnmNamedExprCollection *names)
346 {
347 	if (!names)
348 		return;
349 
350 	g_hash_table_foreach (names->names,
351 			      cb_unlink_all_names,
352 			      NULL);
353 }
354 
355 static void
cb_relink_all_names(G_GNUC_UNUSED gpointer key,gpointer value,G_GNUC_UNUSED gpointer user_data)356 cb_relink_all_names (G_GNUC_UNUSED gpointer key,
357 		     gpointer value,
358 		     G_GNUC_UNUSED gpointer user_data)
359 {
360 	GnmNamedExpr *nexpr = value;
361 	expr_name_relink_deps (nexpr);
362 }
363 
364 void
gnm_named_expr_collection_relink(GnmNamedExprCollection * names)365 gnm_named_expr_collection_relink (GnmNamedExprCollection *names)
366 {
367 	if (!names)
368 		return;
369 
370 	g_hash_table_foreach (names->names,
371 			      cb_relink_all_names,
372 			      NULL);
373 }
374 
375 GnmNamedExpr *
gnm_named_expr_collection_lookup(GnmNamedExprCollection const * scope,char const * name)376 gnm_named_expr_collection_lookup (GnmNamedExprCollection const *scope,
377 				  char const *name)
378 {
379 	if (scope != NULL) {
380 		GOString fake_name;
381 		GnmNamedExpr *nexpr;
382 
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;
391 }
392 
393 static void
cb_list_names(G_GNUC_UNUSED gpointer key,gpointer value,gpointer user_data)394 cb_list_names (G_GNUC_UNUSED gpointer key,
395 	       gpointer value,
396 	       gpointer user_data)
397 {
398 	GSList **pres = user_data;
399 	GO_SLIST_PREPEND (*pres, value);
400 }
401 
402 /**
403  * gnm_named_expr_collection_list:
404  * @scope: #GnmNamedExprCollection
405  *
406  * Returns: (element-type GnmNamedExpr) (transfer container):
407  **/
408 GSList *
gnm_named_expr_collection_list(GnmNamedExprCollection const * scope)409 gnm_named_expr_collection_list (GnmNamedExprCollection const *scope)
410 {
411 	GSList *res = NULL;
412 	if (scope) {
413 		g_hash_table_foreach (scope->names,
414 				      cb_list_names,
415 				      &res);
416 	}
417 	return res;
418 }
419 
420 static void
gnm_named_expr_collection_insert(GnmNamedExprCollection * scope,GnmNamedExpr * nexpr)421 gnm_named_expr_collection_insert (GnmNamedExprCollection *scope,
422 				  GnmNamedExpr *nexpr)
423 {
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);
433 	}
434 
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);
441 }
442 
443 typedef struct {
444 	Sheet const *sheet;
445 	GnmRange const *r;
446 	GnmNamedExpr *res;
447 } CheckName;
448 
449 static void
cb_check_name(G_GNUC_UNUSED gpointer key,GnmNamedExpr * nexpr,CheckName * user)450 cb_check_name (G_GNUC_UNUSED gpointer key, GnmNamedExpr *nexpr,
451 	       CheckName *user)
452 {
453 	GnmValue *v;
454 
455 	if (nexpr->scope == NULL || nexpr->is_hidden || !nexpr->texpr)
456 		return;
457 
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;
473 		}
474 		value_release (v);
475 	}
476 }
477 
478 static GnmNamedExpr *
gnm_named_expr_collection_check(GnmNamedExprCollection * scope,Sheet const * sheet,GnmRange const * r)479 gnm_named_expr_collection_check (GnmNamedExprCollection *scope,
480 				 Sheet const *sheet, GnmRange const *r)
481 {
482 	CheckName user;
483 
484 	if (scope == NULL)
485 		return NULL;
486 
487 	user.sheet = sheet;
488 	user.r	   = r;
489 	user.res   = NULL;
490 
491 	g_hash_table_foreach (scope->names, (GHFunc)cb_check_name, &user);
492 	return user.res;
493 }
494 
495 /**
496  * gnm_named_expr_collection_foreach:
497  * @names: #GnmNamedExprCollection
498  * @func: (scope call):
499  * @data: user data.
500  *
501  * Iterate over all names, including placeholders.
502  **/
503 void
gnm_named_expr_collection_foreach(GnmNamedExprCollection * names,GHFunc func,gpointer data)504 gnm_named_expr_collection_foreach (GnmNamedExprCollection *names,
505 				   GHFunc func,
506 				   gpointer data)
507 {
508 	g_hash_table_foreach (names->names, func, data);
509 	g_hash_table_foreach (names->placeholders, func, data);
510 }
511 
512 /******************************************************************************/
513 
514 /**
515  * expr_name_handle_references:
516  *
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.
521  */
522 static void
expr_name_handle_references(GnmNamedExpr * nexpr,gboolean add)523 expr_name_handle_references (GnmNamedExpr *nexpr, gboolean add)
524 {
525 	GSList *sheets, *ptr;
526 
527 	sheets = gnm_expr_top_referenced_sheets (nexpr->texpr);
528 
529 	for (ptr = sheets ; ptr != NULL ; ptr = ptr->next) {
530 		Sheet *sheet = ptr->data;
531 		GnmNamedExpr *found;
532 
533 		/* Implicit reference.  */
534 		if (!sheet)
535 			continue;
536 
537 		/* No need to do anything during destruction */
538 		if (sheet->deps == NULL)
539 			continue;
540 
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 ?");
547 			}
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);
553 			}
554 		}
555 	}
556 	g_slist_free (sheets);
557 }
558 
559 
560 /**
561  * expr_name_lookup:
562  * @pos: #GnmParsePos identifying a #Sheet or a #Workbook.
563  * @name: name of #GnmNamedExpr to look up.
564  *
565  * Return: (transfer none) (nullable): #GnmNamedExpr named @name in the scope
566  * given by @pos; %NULL if no such #GnmNamedExpr exists.
567  */
568 GnmNamedExpr *
expr_name_lookup(GnmParsePos const * pp,char const * name)569 expr_name_lookup (GnmParsePos const *pp, char const *name)
570 {
571 	GnmNamedExpr *res = NULL;
572 	Sheet const *sheet = NULL;
573 	Workbook const *wb = NULL;
574 
575 	g_return_val_if_fail (name != NULL, NULL);
576 
577 	if (pp != NULL) {
578 		sheet = pp->sheet;
579 		wb = (sheet != NULL) ? sheet->workbook : pp->wb;
580 	}
581 
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;
587 }
588 
589 /**
590  * expr_name_new:
591  * @name:
592  *
593  * Creates a new name without linking it into any container.
594  **/
595 GnmNamedExpr *
expr_name_new(char const * name)596 expr_name_new (char const *name)
597 {
598 	GnmNamedExpr *nexpr;
599 
600 	g_return_val_if_fail (name != NULL, NULL);
601 
602 	nexpr = g_new0 (GnmNamedExpr,1);
603 
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;
613 
614 	if (gnm_debug_flag ("names"))
615 		g_printerr ("Created new name %s\n", name);
616 
617 	return nexpr;
618 }
619 
620 struct cb_name_loop_check {
621 	/* One of these */
622 	char const *name;
623 	GnmNamedExpr *nexpr;
624 
625 	gboolean stop_at_name;
626 	gboolean res;
627 };
628 
629 static GnmExpr const *
cb_name_loop_check(GnmExpr const * expr,GnmExprWalk * data)630 cb_name_loop_check (GnmExpr const *expr, GnmExprWalk *data)
631 {
632 	struct cb_name_loop_check *args = data->user;
633 
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;
643 		}
644 	}
645 
646 	return NULL;
647 }
648 
649 /**
650  * expr_name_check_for_loop:
651  * @name: tentative name
652  * @texpr: tentative expression
653  *
654  * Returns: %TRUE if defining the tentative name would cause a circular
655  * name reference.
656  *
657  * NOTE: if we already have a circular reference beforehand, we will come
658  * to serious grief.
659  */
660 gboolean
expr_name_check_for_loop(char const * name,GnmExprTop const * texpr)661 expr_name_check_for_loop (char const *name, GnmExprTop const *texpr)
662 {
663 	struct cb_name_loop_check args;
664 
665 	g_return_val_if_fail (texpr != NULL, TRUE);
666 
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;
673 }
674 
675 static void
expr_name_queue_deps(GnmNamedExpr * nexpr)676 expr_name_queue_deps (GnmNamedExpr *nexpr)
677 {
678 	if (nexpr->dependents)
679 		g_hash_table_foreach (nexpr->dependents,
680 				      (GHFunc)dependent_queue_recalc,
681 				      NULL);
682 }
683 
684 /**
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:
691  *
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.
695  *
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.
702  **/
703 GnmNamedExpr *
expr_name_add(GnmParsePos const * pp,char const * name,GnmExprTop const * texpr,char ** error_msg,gboolean link_to_container,GnmNamedExpr * stub)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)
708 {
709 	GnmNamedExpr *nexpr = NULL;
710 	GnmNamedExprCollection *scope = NULL;
711 	GOString fake_name;
712 
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);
717 
718 	if (error_msg)
719 		*error_msg = NULL;
720 
721 	fake_name.str = name;
722 
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);
728 	}
729 
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;
737 	}
738 
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;
748 		}
749 
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);
766 
767 				gnm_expr_top_unref (texpr);
768 				return NULL;
769 			}
770 		}
771 	}
772 
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);
782 		}
783 	}
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);
792 
793 	return nexpr;
794 }
795 
796 GnmNamedExpr *
expr_name_ref(GnmNamedExpr * nexpr)797 expr_name_ref (GnmNamedExpr *nexpr)
798 {
799 	g_return_val_if_fail (nexpr != NULL, NULL);
800 	nexpr->ref_count++;
801 	return nexpr;
802 }
803 
804 void
expr_name_unref(GnmNamedExpr * nexpr)805 expr_name_unref (GnmNamedExpr *nexpr)
806 {
807 	g_return_if_fail (nexpr != NULL);
808 
809 	if (nexpr->ref_count-- > 1)
810 		return;
811 
812 	if (gnm_debug_flag ("names"))
813 		g_printerr ("Finalizing name %s\n", nexpr->name->str);
814 
815 	g_return_if_fail (nexpr->scope == NULL);
816 
817 	go_string_unref (nexpr->name);
818 	nexpr->name = NULL;
819 
820 	if (nexpr->texpr != NULL)
821 		expr_name_set_expr (nexpr, NULL);
822 
823 	if (nexpr->dependents != NULL) {
824 		g_hash_table_destroy (nexpr->dependents);
825 		nexpr->dependents  = NULL;
826 	}
827 
828 	nexpr->pos.wb      = NULL;
829 	nexpr->pos.sheet   = NULL;
830 
831 	g_free (nexpr);
832 }
833 
834 GType
gnm_named_expr_get_type(void)835 gnm_named_expr_get_type (void)
836 {
837 	static GType t = 0;
838 
839 	if (t == 0) {
840 		t = g_boxed_type_register_static ("GnmNamedExpr",
841 			 (GBoxedCopyFunc)expr_name_ref,
842 			 (GBoxedFreeFunc)expr_name_unref);
843 	}
844 	return t;
845 }
846 
847 /**
848  * expr_name_remove:
849  * @nexpr:
850  *
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!
854  **/
855 void
expr_name_remove(GnmNamedExpr * nexpr)856 expr_name_remove (GnmNamedExpr *nexpr)
857 {
858 	g_return_if_fail (nexpr != NULL);
859 	g_return_if_fail (nexpr->scope != NULL);
860 
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" : "");
865 	}
866 
867 	g_hash_table_remove (
868 		nexpr->is_placeholder ? nexpr->scope->placeholders : nexpr->scope->names,
869 		nexpr->name);
870 }
871 
872 const char *
expr_name_name(GnmNamedExpr const * nexpr)873 expr_name_name (GnmNamedExpr const *nexpr)
874 {
875 	g_return_val_if_fail (nexpr != NULL, NULL);
876 	return nexpr->name->str;
877 }
878 
879 /**
880  * expr_name_set_name:
881  * @nexpr: the named expression
882  * @new_name: the new name of the expression
883  *
884  * returns: TRUE on error.
885  */
886 gboolean
expr_name_set_name(GnmNamedExpr * nexpr,const char * new_name)887 expr_name_set_name (GnmNamedExpr *nexpr,
888 		    const char *new_name)
889 {
890 	const char *old_name;
891 	GHashTable *h;
892 	GOString fake_new_name;
893 
894 	g_return_val_if_fail (nexpr != NULL, TRUE);
895 	g_return_val_if_fail (nexpr->scope == NULL || new_name, TRUE);
896 
897 	old_name = nexpr->name->str;
898 	if (go_str_compare (new_name, old_name) == 0)
899 		return FALSE;
900 
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;
919 		}
920 
921 		g_hash_table_steal (h, nexpr->name);
922 	}
923 
924 	go_string_unref (nexpr->name);
925 	nexpr->name = go_string_new (new_name);
926 
927 	if (h)
928 		g_hash_table_insert (h, (gpointer)nexpr->name, nexpr);
929 
930 	return FALSE;
931 }
932 
933 
934 /**
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
939  *
940  * Returns: (transfer full): The rendering of @nexpr given convention @fmt.
941  */
942 char *
expr_name_as_string(GnmNamedExpr const * nexpr,GnmParsePos const * pp,GnmConventions const * fmt)943 expr_name_as_string (GnmNamedExpr const *nexpr, GnmParsePos const *pp,
944 		     GnmConventions const *fmt)
945 {
946 	if (pp == NULL)
947 		pp = &nexpr->pos;
948 	return gnm_expr_top_as_string (nexpr->texpr, pp, fmt);
949 }
950 
951 /**
952  * expr_name_eval:
953  * @nexpr: A #GnmNamedExpr
954  * @pos: Position where evaluation takes place
955  * @flags: #GnmExprEvalFlags flags describing context.
956  *
957  * Returns: (transfer full): The resulting value.
958  */
959 GnmValue *
expr_name_eval(GnmNamedExpr const * nexpr,GnmEvalPos const * pos,GnmExprEvalFlags flags)960 expr_name_eval (GnmNamedExpr const *nexpr, GnmEvalPos const *pos,
961 		GnmExprEvalFlags flags)
962 {
963 	g_return_val_if_fail (pos, NULL);
964 
965 	if (!nexpr)
966 		return value_new_error_NAME (pos);
967 
968 	return gnm_expr_top_eval (nexpr->texpr, pos, flags);
969 }
970 
971 /**
972  * expr_name_downgrade_to_placeholder:
973  * @nexpr:
974  *
975  * Takes a real non-placeholder name and converts it to being a placeholder.
976  * unrefing its expression
977  **/
978 void
expr_name_downgrade_to_placeholder(GnmNamedExpr * nexpr)979 expr_name_downgrade_to_placeholder (GnmNamedExpr *nexpr)
980 {
981 	g_return_if_fail (nexpr != NULL);
982 
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)));
987 }
988 
989 /*******************************************************************
990  * Manage things that depend on named expressions.
991  */
992 /**
993  * expr_name_set_pos:
994  * @nexpr: the named expression
995  * @pp: the new position
996  *
997  * Returns a translated error string which the caller must free if something
998  * goes wrong.
999  **/
1000 char *
expr_name_set_pos(GnmNamedExpr * nexpr,GnmParsePos const * pp)1001 expr_name_set_pos (GnmNamedExpr *nexpr, GnmParsePos const *pp)
1002 {
1003 	GnmNamedExprCollection *old_scope, *new_scope;
1004 
1005 	g_return_val_if_fail (nexpr != NULL, NULL);
1006 	g_return_val_if_fail (pp != NULL, NULL);
1007 
1008 	old_scope = nexpr->scope;
1009 	new_scope = pp->sheet ? pp->sheet->names : pp->wb->names;
1010 
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);
1018 	}
1019 
1020 	if (old_scope)
1021 		g_hash_table_steal
1022 			(nexpr->is_placeholder ? old_scope->placeholders : old_scope->names,
1023 			 nexpr->name);
1024 
1025 	nexpr->pos = *pp;
1026 	gnm_named_expr_collection_insert (new_scope, nexpr);
1027 	return NULL;
1028 }
1029 
1030 /**
1031  * expr_name_set_expr:
1032  * @nexpr: #GnmNamedExpr to change
1033  * @texpr: (transfer full) (nullable): the new contents
1034  *
1035  * Set the content of @nexpr to @texpr.
1036  **/
1037 void
expr_name_set_expr(GnmNamedExpr * nexpr,GnmExprTop const * texpr)1038 expr_name_set_expr (GnmNamedExpr *nexpr, GnmExprTop const *texpr)
1039 {
1040 	GSList *good = NULL;
1041 
1042 	g_return_if_fail (nexpr != NULL);
1043 
1044 	if (texpr == nexpr->texpr)
1045 		return;
1046 	if (nexpr->texpr != NULL) {
1047 		GSList *deps = NULL, *junk = NULL;
1048 
1049 		deps = expr_name_unlink_deps (nexpr);
1050 		expr_name_handle_references (nexpr, FALSE);
1051 		gnm_expr_top_unref (nexpr->texpr);
1052 
1053 		/*
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.
1057 		 */
1058 		while (deps) {
1059 			GSList *next = deps->next;
1060 			GnmDependent *dep = deps->data;
1061 
1062 			if (dep->sheet && dep->sheet->being_invalidated)
1063 				deps->next = junk, junk = deps;
1064 			else
1065 				deps->next = good, good = deps;
1066 
1067 			deps = next;
1068 		}
1069 
1070 		g_slist_free (junk);
1071 	}
1072 	nexpr->texpr = texpr;
1073 	dependents_link (good);
1074 	g_slist_free (good);
1075 
1076 	if (texpr != NULL)
1077 		expr_name_handle_references (nexpr, TRUE);
1078 
1079 	expr_name_queue_deps (nexpr);
1080 }
1081 
1082 void
expr_name_add_dep(GnmNamedExpr * nexpr,GnmDependent * dep)1083 expr_name_add_dep (GnmNamedExpr *nexpr, GnmDependent *dep)
1084 {
1085 	if (nexpr->dependents == NULL)
1086 		nexpr->dependents = g_hash_table_new (g_direct_hash,
1087 						      g_direct_equal);
1088 
1089 	g_hash_table_insert (nexpr->dependents, dep, dep);
1090 }
1091 
1092 void
expr_name_remove_dep(GnmNamedExpr * nexpr,GnmDependent * dep)1093 expr_name_remove_dep (GnmNamedExpr *nexpr, GnmDependent *dep)
1094 {
1095 	g_return_if_fail (nexpr->dependents != NULL);
1096 
1097 	g_hash_table_remove (nexpr->dependents, dep);
1098 }
1099 
1100 /**
1101  * expr_name_is_placeholder:
1102  * @ne:
1103  *
1104  * Returns: %TRUE if @ne is a placeholder for an unknown name
1105  **/
1106 gboolean
expr_name_is_placeholder(GnmNamedExpr const * nexpr)1107 expr_name_is_placeholder (GnmNamedExpr const *nexpr)
1108 {
1109 	g_return_val_if_fail (nexpr != NULL, FALSE);
1110 
1111 	return (nexpr->texpr &&
1112 		gnm_expr_top_is_err (nexpr->texpr, GNM_ERROR_NAME));
1113 }
1114 
1115 void
expr_name_set_is_placeholder(GnmNamedExpr * nexpr,gboolean is_placeholder)1116 expr_name_set_is_placeholder (GnmNamedExpr *nexpr, gboolean is_placeholder)
1117 {
1118 	g_return_if_fail (nexpr != NULL);
1119 
1120 	is_placeholder = !!is_placeholder;
1121 	if (nexpr->is_placeholder == is_placeholder)
1122 		return;
1123 	nexpr->is_placeholder = is_placeholder;
1124 
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);
1131 	}
1132 }
1133 
1134 gboolean
expr_name_is_active(GnmNamedExpr const * nexpr)1135 expr_name_is_active (GnmNamedExpr const *nexpr)
1136 {
1137 	g_return_val_if_fail (nexpr != NULL, FALSE);
1138 	return nexpr->scope != NULL;
1139 }
1140 
1141 struct cb_expr_name_in_use {
1142 	GnmNamedExpr *nexpr;
1143 	gboolean in_use;
1144 };
1145 
1146 static void
cb_expr_name_in_use(G_GNUC_UNUSED gconstpointer key,GnmNamedExpr * nexpr,struct cb_expr_name_in_use * pdata)1147 cb_expr_name_in_use (G_GNUC_UNUSED gconstpointer key,
1148 		     GnmNamedExpr *nexpr,
1149 		     struct cb_expr_name_in_use *pdata)
1150 {
1151 	if (!pdata->in_use) {
1152 		struct cb_name_loop_check args;
1153 
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;
1160 	}
1161 }
1162 
1163 /**
1164  * expr_name_in_use:
1165  * @nexpr: A named expression.
1166  *
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.
1170  */
1171 
1172 gboolean
expr_name_in_use(GnmNamedExpr * nexpr)1173 expr_name_in_use (GnmNamedExpr *nexpr)
1174 {
1175 	Workbook *wb;
1176 	struct cb_expr_name_in_use data;
1177 
1178 	if (nexpr->dependents != NULL &&
1179 	    g_hash_table_size (nexpr->dependents) != 0)
1180 		return TRUE;
1181 
1182 	data.nexpr = nexpr;
1183 	data.in_use = FALSE;
1184 
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);
1189 
1190 	return data.in_use;
1191 }
1192 
1193 
1194 int
expr_name_cmp_by_name(GnmNamedExpr const * a,GnmNamedExpr const * b)1195 expr_name_cmp_by_name (GnmNamedExpr const *a, GnmNamedExpr const *b)
1196 {
1197 	Sheet const *sheeta = a->pos.sheet;
1198 	Sheet const *sheetb = b->pos.sheet;
1199 	int res = 0;
1200 
1201 	if (sheeta != sheetb) {
1202 		/* Locals after non-locals.  */
1203 		if (!sheeta || !sheetb)
1204 			return (!sheeta) - (!sheetb);
1205 
1206 		/* By non-local sheet order.  */
1207 		res = g_utf8_collate (sheeta->name_case_insensitive,
1208 				      sheetb->name_case_insensitive);
1209 	}
1210 
1211 	if (res == 0)	/* By name.  */
1212 		res = go_utf8_collate_casefold (a->name->str, b->name->str);
1213 
1214 	return res;
1215 }
1216 
1217 /**
1218  * sheet_names_check:
1219  * @sheet: #Sheet
1220  * @r: #GnmRange
1221  *
1222  * Returns: (transfer none) (nullable): The name of a #GnmNamedExpr if
1223  * @sheet!@r is the target of a named range.
1224  *
1225  * Preference is given to workbook scope over sheet.
1226  **/
1227 char const *
sheet_names_check(Sheet const * sheet,GnmRange const * r)1228 sheet_names_check (Sheet const *sheet, GnmRange const *r)
1229 {
1230 	GnmNamedExpr *nexpr;
1231 	GnmRange tmp;
1232 
1233 	g_return_val_if_fail (IS_SHEET (sheet), NULL);
1234 	g_return_val_if_fail (r != NULL, NULL);
1235 
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;
1245 	}
1246 
1247 	return (nexpr != NULL) ? nexpr->name->str : NULL;
1248 }
1249 
1250 
1251 /**
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
1256  *
1257  * This is a wrapper around expr_name_add to set this as permanent name.
1258  *
1259  *
1260  **/
1261 void
expr_name_perm_add(Sheet * sheet,char const * name,GnmExprTop const * value,gboolean is_editable)1262 expr_name_perm_add (Sheet *sheet, char const *name,
1263 		    GnmExprTop const *value,
1264 		    gboolean is_editable)
1265 {
1266 	GnmNamedExpr *res;
1267 	GnmParsePos pp;
1268 
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;
1274 	}
1275 }
1276 
1277 /* ------------------------------------------------------------------------- */
1278 
1279 static void
expr_name_set_expr_ref(GnmNamedExpr * nexpr,GnmExprTop const * texpr)1280 expr_name_set_expr_ref (GnmNamedExpr *nexpr, GnmExprTop const *texpr)
1281 {
1282 	gnm_expr_top_ref (texpr);
1283 	expr_name_set_expr (nexpr, texpr);
1284 }
1285 
1286 /**
1287  * expr_name_set_expr_undo_new:
1288  * @nexpr: #GnmNamedExpr
1289  *
1290  * Returns: (transfer full):
1291  **/
1292 GOUndo *
expr_name_set_expr_undo_new(GnmNamedExpr * ne)1293 expr_name_set_expr_undo_new (GnmNamedExpr *ne)
1294 {
1295 	expr_name_ref (ne);
1296 	gnm_expr_top_ref (ne->texpr);
1297 
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);
1302 }
1303 
1304 /* ------------------------------------------------------------------------- */
1305