1This file is declare.def, from which is created declare.c.
2It implements the builtins "declare" and "local" in Bash.
3
4Copyright (C) 1987-2020 Free Software Foundation, Inc.
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
8Bash is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
12
13Bash is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with Bash.  If not, see <http://www.gnu.org/licenses/>.
20
21$PRODUCES declare.c
22
23$BUILTIN declare
24$FUNCTION declare_builtin
25$SHORT_DOC declare [-aAfFgiIlnrtux] [-p] [name[=value] ...]
26Set variable values and attributes.
27
28Declare variables and give them attributes.  If no NAMEs are given,
29display the attributes and values of all variables.
30
31Options:
32  -f	restrict action or display to function names and definitions
33  -F	restrict display to function names only (plus line number and
34		source file when debugging)
35  -g	create global variables when used in a shell function; otherwise
36		ignored
37  -I	if creating a local variable, inherit the attributes and value
38		of a variable with the same name at a previous scope
39  -p	display the attributes and value of each NAME
40
41Options which set attributes:
42  -a	to make NAMEs indexed arrays (if supported)
43  -A	to make NAMEs associative arrays (if supported)
44  -i	to make NAMEs have the `integer' attribute
45  -l	to convert the value of each NAME to lower case on assignment
46  -n	make NAME a reference to the variable named by its value
47  -r	to make NAMEs readonly
48  -t	to make NAMEs have the `trace' attribute
49  -u	to convert the value of each NAME to upper case on assignment
50  -x	to make NAMEs export
51
52Using `+' instead of `-' turns off the given attribute.
53
54Variables with the integer attribute have arithmetic evaluation (see
55the `let' command) performed when the variable is assigned a value.
56
57When used in a function, `declare' makes NAMEs local, as with the `local'
58command.  The `-g' option suppresses this behavior.
59
60Exit Status:
61Returns success unless an invalid option is supplied or a variable
62assignment error occurs.
63$END
64
65$BUILTIN typeset
66$FUNCTION declare_builtin
67$SHORT_DOC typeset [-aAfFgiIlnrtux] [-p] name[=value] ...
68Set variable values and attributes.
69
70A synonym for `declare'.  See `help declare'.
71$END
72
73#include <config.h>
74
75#if defined (HAVE_UNISTD_H)
76#  ifdef _MINIX
77#    include <sys/types.h>
78#  endif
79#  include <unistd.h>
80#endif
81
82#include <stdio.h>
83
84#include "../bashansi.h"
85#include "../bashintl.h"
86
87#include "../shell.h"
88#include "../flags.h"
89#include "common.h"
90#include "builtext.h"
91#include "bashgetopt.h"
92
93static SHELL_VAR *declare_find_variable PARAMS((const char *, int, int));
94static int declare_internal PARAMS((register WORD_LIST *, int));
95
96/* Declare or change variable attributes. */
97int
98declare_builtin (list)
99     register WORD_LIST *list;
100{
101  return (declare_internal (list, 0));
102}
103
104$BUILTIN local
105$FUNCTION local_builtin
106$SHORT_DOC local [option] name[=value] ...
107Define local variables.
108
109Create a local variable called NAME, and give it VALUE.  OPTION can
110be any option accepted by `declare'.
111
112Local variables can only be used within a function; they are visible
113only to the function where they are defined and its children.
114
115Exit Status:
116Returns success unless an invalid option is supplied, a variable
117assignment error occurs, or the shell is not executing a function.
118$END
119int
120local_builtin (list)
121     register WORD_LIST *list;
122{
123  /* Catch a straight `local --help' before checking function context */
124  if (list && list->word && STREQ (list->word->word, "--help"))
125    {
126      builtin_help ();
127      return (EX_USAGE);
128    }
129
130  if (variable_context)
131    return (declare_internal (list, 1));
132  else
133    {
134      builtin_error (_("can only be used in a function"));
135      return (EXECUTION_FAILURE);
136    }
137}
138
139#if defined (ARRAY_VARS)
140#  define DECLARE_OPTS	"+acfgilnprtuxAFGI"
141#else
142#  define DECLARE_OPTS	"+cfgilnprtuxFGI"
143#endif
144
145static SHELL_VAR *
146declare_find_variable (name, mkglobal, chklocal)
147     const char *name;
148     int mkglobal, chklocal;
149{
150  SHELL_VAR *var;
151
152  if (mkglobal == 0)
153    return (find_variable (name));
154  else if (chklocal)
155    {
156      var = find_variable (name);
157      if (var && local_p (var) && var->context == variable_context)
158	return var;
159      return (find_global_variable (name));
160    }
161  else
162    return (find_global_variable (name));
163}
164
165/* The workhorse function. */
166static int
167declare_internal (list, local_var)
168     register WORD_LIST *list;
169     int local_var;
170{
171  int flags_on, flags_off, *flags;
172  int any_failed, assign_error, pflag, nodefs, opt, onref, offref;
173  int mkglobal, chklocal, inherit_flag;
174  char *t, *subscript_start;
175  SHELL_VAR *var, *refvar, *v;
176  FUNCTION_DEF *shell_fn;
177
178  flags_on = flags_off = any_failed = assign_error = pflag = nodefs = 0;
179  mkglobal = chklocal = inherit_flag = 0;
180  refvar = (SHELL_VAR *)NULL;
181  reset_internal_getopt ();
182  while ((opt = internal_getopt (list, DECLARE_OPTS)) != -1)
183    {
184      flags = list_opttype == '+' ? &flags_off : &flags_on;
185
186      /* If you add options here, see whether or not they need to be added to
187	 the loop in subst.c:shell_expand_word_list() */
188      switch (opt)
189	{
190	case 'a':
191#if defined (ARRAY_VARS)
192	  *flags |= att_array;
193	  break;
194#else
195	  builtin_usage ();
196	  return (EX_USAGE);
197#endif
198	case 'A':
199#if defined (ARRAY_VARS)
200	  *flags |= att_assoc;
201	  break;
202#else
203	  builtin_usage ();
204	  return (EX_USAGE);
205#endif
206	case 'p':
207/*	  if (local_var == 0) */
208	    pflag++;
209	  break;
210        case 'F':
211	  nodefs++;
212	  *flags |= att_function;
213	  break;
214	case 'f':
215	  *flags |= att_function;
216	  break;
217	case 'G':
218	  if (flags == &flags_on)
219	    chklocal = 1;
220	  /*FALLTHROUGH*/
221	case 'g':
222	  if (flags == &flags_on)
223	    mkglobal = 1;
224	  break;
225	case 'i':
226	  *flags |= att_integer;
227	  break;
228	case 'n':
229	  *flags |= att_nameref;
230	  break;
231	case 'r':
232	  *flags |= att_readonly;
233	  break;
234	case 't':
235	  *flags |= att_trace;
236	  break;
237	case 'x':
238	  *flags |= att_exported;
239	  array_needs_making = 1;
240	  break;
241#if defined (CASEMOD_ATTRS)
242#  if defined (CASEMOD_CAPCASE)
243	 case 'c':
244	  *flags |= att_capcase;
245	  if (flags == &flags_on)
246	    flags_off |= att_uppercase|att_lowercase;
247	  break;
248#  endif
249	case 'l':
250	  *flags |= att_lowercase;
251	  if (flags == &flags_on)
252	    flags_off |= att_capcase|att_uppercase;
253	  break;
254	case 'u':
255	  *flags |= att_uppercase;
256	  if (flags == &flags_on)
257	    flags_off |= att_capcase|att_lowercase;
258	  break;
259#endif /* CASEMOD_ATTRS */
260	case 'I':
261	  inherit_flag = MKLOC_INHERIT;
262	  break;
263	CASE_HELPOPT;
264	default:
265	  builtin_usage ();
266	  return (EX_USAGE);
267	}
268    }
269
270  list = loptend;
271
272  /* If there are no more arguments left, then we just want to show
273     some variables. */
274  if (list == 0)	/* declare -[aAfFirtx] */
275    {
276      /* Show local variables defined at this context level if this is
277	 the `local' builtin. */
278      if (local_var)
279	show_local_var_attributes (0, nodefs);	/* XXX - fix up args later */
280      else if (pflag && (flags_on == 0 || flags_on == att_function))
281	show_all_var_attributes (flags_on == 0, nodefs);
282      else if (flags_on == 0)
283	return (set_builtin ((WORD_LIST *)NULL));
284      else
285	set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
286
287      return (sh_chkwrite (EXECUTION_SUCCESS));
288    }
289
290  if (pflag)	/* declare -p [-aAfFirtx] name [name...] */
291    {
292      for (any_failed = 0; list; list = list->next)
293	{
294	  if (flags_on & att_function)
295	    pflag = show_func_attributes (list->word->word, nodefs);
296	  else if (local_var)
297	    pflag = show_localname_attributes (list->word->word, nodefs);
298	  else
299	    pflag = show_name_attributes (list->word->word, nodefs);
300	  if (pflag)
301	    {
302	      sh_notfound (list->word->word);
303	      any_failed++;
304	    }
305	}
306      return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS));
307    }
308
309#define NEXT_VARIABLE() free (name); list = list->next; continue
310
311  /* There are arguments left, so we are making variables. */
312  while (list)		/* declare [-aAfFirx] name [name ...] */
313    {
314      char *value, *name, *oldname;
315      int offset, aflags, wflags, created_var, namelen;
316      int assoc_noexpand;
317#if defined (ARRAY_VARS)
318      int making_array_special, compound_array_assign, simple_array_assign;
319      int var_exists, array_exists, creating_array, array_subscript_assignment;
320#endif
321
322      name = savestring (list->word->word);
323      wflags = list->word->flags;
324#if defined (ARRAY_VARS)
325      assoc_noexpand = assoc_expand_once && (wflags & W_ASSIGNMENT);
326#else
327      assoc_noexpand = 0;
328#endif
329      offset = assignment (name, assoc_noexpand ? 2 : 0);
330      aflags = 0;
331      created_var = 0;
332
333      if (local_var && variable_context && STREQ (name, "-"))
334	{
335	  var = make_local_variable ("-", 0);
336	  FREE (value_cell (var));		/* just in case */
337	  value = get_current_options ();
338	  var_setvalue (var, value);
339	  VSETATTR (var, att_invisible);
340	  NEXT_VARIABLE ();
341	}
342
343      if (offset)	/* declare [-aAfFirx] name=value */
344	{
345	  name[offset] = '\0';
346	  value = name + offset + 1;
347	  if (name[offset - 1] == '+')
348	    {
349	      aflags |= ASS_APPEND;
350	      name[offset - 1] = '\0';
351	    }
352	}
353      else
354	value = "";
355
356      /* Do some lexical error checking on the LHS and RHS of the assignment
357	 that is specific to nameref variables. */
358      if (flags_on & att_nameref)
359	{
360#if defined (ARRAY_VARS)
361	  if (valid_array_reference (name, 0))
362	    {
363	      builtin_error (_("%s: reference variable cannot be an array"), name);
364	      assign_error++;
365	      NEXT_VARIABLE ();
366	    }
367	  else
368#endif
369	  /* disallow self references at global scope, warn at function scope */
370	  if (check_selfref (name, value, 0))
371	    {
372	      if (variable_context == 0)
373		{
374		  builtin_error (_("%s: nameref variable self references not allowed"), name);
375		  assign_error++;
376		  NEXT_VARIABLE ();
377		}
378	      else
379		builtin_warning (_("%s: circular name reference"), name);
380	    }
381#if 1
382	  if (value && *value && (aflags & ASS_APPEND) == 0 && valid_nameref_value (value, 1) == 0)
383	    {
384	      builtin_error (_("`%s': invalid variable name for name reference"), value);
385	      assign_error++;
386	      NEXT_VARIABLE ();
387	    }
388#endif
389	}
390
391restart_new_var_name:
392#if defined (ARRAY_VARS)
393      var_exists = array_exists = creating_array = 0;
394      compound_array_assign = simple_array_assign = 0;
395      array_subscript_assignment = 0;
396      subscript_start = (char *)NULL;
397      if ((t = strchr (name, '[')) && (flags_on & att_function) == 0)	/* ] */
398	{
399	  /* If offset != 0 we have already validated any array reference
400	     because assignment() calls skipsubscript() */
401	  if (offset == 0 && valid_array_reference (name, 0) == 0)
402	    {
403	      sh_invalidid (name);
404	      assign_error++;
405	      NEXT_VARIABLE ();
406	    }
407	  subscript_start = t;
408	  *t = '\0';
409	  making_array_special = 1;	/* XXX - should this check offset? */
410	  array_subscript_assignment = offset != 0;
411	}
412      else
413	making_array_special = 0;
414#endif
415
416      /* If we're in posix mode or not looking for a shell function (since
417	 shell function names don't have to be valid identifiers when the
418	 shell's not in posix mode), check whether or not the argument is a
419	 valid, well-formed shell identifier. */
420      if ((posixly_correct || (flags_on & att_function) == 0) && legal_identifier (name) == 0)
421	{
422	  sh_invalidid (name);
423	  assign_error++;
424	  NEXT_VARIABLE ();
425	}
426
427      /* If VARIABLE_CONTEXT has a non-zero value, then we are executing
428	 inside of a function.  This means we should make local variables,
429	 not global ones. */
430
431      /* XXX - this has consequences when we're making a local copy of a
432	       variable that was in the temporary environment.  Watch out
433	       for this. */
434      refvar = (SHELL_VAR *)NULL;
435      if (variable_context && mkglobal == 0 && ((flags_on & att_function) == 0))
436	{
437	  char *newname;
438
439	  /* check name for validity here? */
440	  var = find_variable (name);
441	  if (var == 0)
442	    newname = nameref_transform_name (name, ASS_MKLOCAL);
443	  else if ((flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0)
444	    {
445	      /* Ok, we're following namerefs here, so let's make sure that if
446		 we followed one, it was at the same context (see below for
447		 more details). */
448	      refvar = find_variable_last_nameref (name, 1);
449	      newname = (refvar && refvar->context != variable_context) ? name : var->name;
450	      refvar = (SHELL_VAR *)NULL;
451	    }
452	  else
453	    newname = name;	/* dealing with nameref attribute */
454
455#if defined (ARRAY_VARS)
456	  /* Pass 1 as second argument to make_local_{assoc,array}_variable
457	     return an existing {array,assoc} variable to be flagged as an
458	     error below. */
459	  if (flags_on & att_assoc)
460	    var = make_local_assoc_variable (newname, MKLOC_ARRAYOK|inherit_flag);
461	  else if ((flags_on & att_array) || making_array_special)
462	    var = make_local_array_variable (newname, MKLOC_ASSOCOK|inherit_flag);
463	  else
464#endif
465	  if (offset == 0 && (flags_on & att_nameref))
466	    {
467	      /* First look for refvar at current scope */
468	      refvar = find_variable_last_nameref (name, 1);
469	      /* VARIABLE_CONTEXT != 0, so we are attempting to create or modify
470		 the attributes for a local variable at the same scope.  If we've
471		 used a reference from a previous context to resolve VAR, we
472		 want to throw REFVAR and VAR away and create a new local var. */
473	      if (refvar && refvar->context != variable_context)
474		{
475		  refvar = 0;
476		  var = make_local_variable (name, inherit_flag);
477		}
478	      else if (refvar && refvar->context == variable_context)
479		var = refvar;
480	      /* Maybe we just want to create a new local variable */
481	      else if (var == 0 || var->context != variable_context)
482		var = make_local_variable (name, inherit_flag);
483	      /* otherwise we have a var at the right context */
484	    }
485	  else
486	    /* XXX - check name for validity here with valid_nameref_value */
487	    var = make_local_variable ((flags_on & att_nameref) ? name : newname, inherit_flag);	/* sets att_invisible for new vars */
488
489	  if (var == 0)
490	    {
491	      any_failed++;
492	      NEXT_VARIABLE ();
493	    }
494	  if (var && nameref_p (var) && readonly_p (var) && nameref_cell (var) && (flags_off & att_nameref))
495	    {
496	      sh_readonly (name);
497	      any_failed++;
498	      NEXT_VARIABLE ();
499	    }
500	}
501      else
502	var = (SHELL_VAR *)NULL;
503
504      /* If we are declaring a function, then complain about it in some way.
505	 We don't let people make functions by saying `typeset -f foo=bar'. */
506
507      /* There should be a way, however, to let people look at a particular
508	 function definition by saying `typeset -f foo'. */
509
510      if (flags_on & att_function)
511	{
512	  if (offset)	/* declare -f [-rix] foo=bar */
513	    {
514	      builtin_error (_("cannot use `-f' to make functions"));
515	      free (name);
516	      return (EXECUTION_FAILURE);
517	    }
518	  else		/* declare -f [-rx] name [name...] */
519	    {
520	      var = find_function (name);
521
522	      if (var)
523		{
524		  if (readonly_p (var) && (flags_off & att_readonly))
525		    {
526		      builtin_error (_("%s: readonly function"), name);
527		      any_failed++;
528		      NEXT_VARIABLE ();
529		    }
530		  else if (flags_on & (att_array|att_assoc))
531		    {
532		      sh_invalidopt ((flags_on & att_array) ? "-a" : "-A");
533		      any_failed++;
534		      NEXT_VARIABLE ();
535		    }
536		  /* declare -[Ff] name [name...] */
537		  if (flags_on == att_function && flags_off == 0)
538		    {
539#if defined (DEBUGGER)
540		      if (nodefs && debugging_mode)
541			{
542			  shell_fn = find_function_def (var->name);
543			  if (shell_fn)
544			    printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file);
545			  else
546			    printf ("%s\n", var->name);
547			}
548		      else
549#endif /* DEBUGGER */
550			{
551			  t = nodefs ? var->name
552				     : named_function_string (name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL);
553			  printf ("%s\n", t);
554			  any_failed = sh_chkwrite (any_failed);
555			}
556		    }
557		  else		/* declare -[fF] -[rx] name [name...] */
558		    {
559		      VSETATTR (var, flags_on);
560		      flags_off &= ~att_function;	/* makes no sense */
561		      VUNSETATTR (var, flags_off);
562		    }
563		}
564	      else
565		any_failed++;
566	      NEXT_VARIABLE ();
567	    }
568	}
569      else		/* declare -[aAinrx] name [name...] */
570	{
571	  /* Non-null if we just created or fetched a local variable. */
572#if 0
573	  /* This is bash-4.3 code. */
574	  /* Here's what ksh93 seems to do.  If we are modifying an existing
575	     nameref variable, we don't follow the nameref chain past the last
576	     nameref, and we set the nameref variable's value so future
577	     references to that variable will return the value of the variable
578	     we're assigning right now. */
579#else
580	  /* Here's what ksh93 seems to do as of the 2012 version: if we are
581	     using declare -n to modify the value of an existing nameref
582	     variable, don't follow the nameref chain at all and just search
583	     for a nameref at the current context.  If we have a nameref,
584	     modify its value (changing which variable it references). */
585#endif
586	  if (var == 0 && (flags_on & att_nameref))
587	    {
588	      /* See if we are trying to modify an existing nameref variable,
589		 but don't follow the nameref chain. */
590	      var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name);
591	      if (var && nameref_p (var) == 0)
592		var = 0;
593	    }
594	  /* However, if we're turning off the nameref attribute on an existing
595	     nameref variable, we first follow the nameref chain to the end,
596	     modify the value of the variable this nameref variable references
597	     if there is an assignment statement argument,
598	     *CHANGING ITS VALUE AS A SIDE EFFECT*, then turn off the nameref
599	     flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */
600	  else if (var == 0 && (flags_off & att_nameref))
601	    {
602	      /* See if we are trying to modify an existing nameref variable */
603	      refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0);
604	      if (refvar && nameref_p (refvar) == 0)
605		refvar = 0;
606	      /* If the nameref is readonly but doesn't have a value, ksh93
607		 allows the nameref attribute to be removed.  If it's readonly
608		 and has a value, even if the value doesn't reference an
609		 existing variable, we disallow the modification */
610	      if (refvar && nameref_cell (refvar) && readonly_p (refvar))
611		{
612		  sh_readonly (name);
613		  any_failed++;
614		  NEXT_VARIABLE ();
615		}
616
617	      /* If all we're doing is turning off the nameref attribute, don't
618		 bother with VAR at all, whether it exists or not. Just turn it
619		 off and go on. */
620	      if (refvar && flags_on == 0 && offset == 0 && (flags_off & ~att_nameref) == 0)
621		{
622		  VUNSETATTR (refvar, att_nameref);
623		  NEXT_VARIABLE ();
624		}
625
626	      if (refvar)
627		/* XXX - use declare_find_variable here? */
628		var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
629	    }
630#if defined (ARRAY_VARS)
631	  /* If we have an array assignment to a nameref, remove the nameref
632	     attribute and go on. */
633	  else if (var == 0 && offset && array_subscript_assignment)
634	    {
635	      var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name);
636	      if (var && nameref_p (var))
637		{
638		  internal_warning (_("%s: removing nameref attribute"), name);
639		  FREE (value_cell (var));		/* XXX - bash-4.3 compat */
640		  var_setvalue (var, (char *)NULL);
641		  VUNSETATTR (var, att_nameref);
642		}
643	    }
644#endif
645
646	  /* See if we are trying to set flags or value (or create) for an
647	     existing nameref that points to a non-existent variable: e.g.,
648		declare -n foo=bar
649		unset foo	# unsets bar
650		declare -i foo
651		foo=4+4
652		declare -p foo */
653	  if (var == 0 && (mkglobal || flags_on || flags_off || offset))
654	    {
655	      refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0);
656	      if (refvar && nameref_p (refvar) == 0)
657		refvar = 0;
658	      if (refvar)
659		/* XXX - use declare_find_variable here? */
660		var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
661	      if (refvar && var == 0)
662		{
663		  oldname = name;	/* need to free this */
664
665		  namelen = strlen (nameref_cell (refvar));
666#if defined (ARRAY_VARS)
667		  if (subscript_start)
668		    {
669		      *subscript_start = '[';		/*]*/
670		      namelen +=  strlen (subscript_start);
671		    }
672#endif
673		  name = xmalloc (namelen + 2 + strlen (value) + 1);
674		  strcpy (name, nameref_cell (refvar));
675#if defined (ARRAY_VARS)
676		  if (subscript_start)
677		    strcpy (name + strlen (nameref_cell (refvar)), subscript_start);
678#endif
679		  /* We are committed to using the new name, so reset */
680		  if (offset)
681		    {
682		      /* Rebuild assignment and restore offset and value */
683		      if (aflags & ASS_APPEND)
684			name[namelen++] = '+';
685		      name[namelen++] = '=';
686		      if (value && *value)
687			strcpy (name + namelen, value);
688		      else
689			name[namelen] = '\0';
690		      offset = assignment (name, 0);
691		      /* if offset was valid previously, but the substituting
692			 of the nameref value results in an invalid assignment,
693			 throw an invalid identifier error */
694		      if (offset == 0)
695			{
696			  free (oldname);
697			  sh_invalidid (name);
698			  assign_error++;
699			  NEXT_VARIABLE ();
700			}
701		      name[offset] = '\0';
702		      value = name + namelen;
703		    }
704		  free (oldname);
705
706		  /* OK, let's turn off the nameref attribute.
707		     Now everything else applies to VAR. */
708		  if (flags_off & att_nameref)
709		    VUNSETATTR (refvar, att_nameref);
710
711		  goto restart_new_var_name;
712		  /* NOTREACHED */
713		}
714	    }
715	  if (var == 0)
716	    var = declare_find_variable (name, mkglobal, chklocal);
717
718#if defined (ARRAY_VARS)
719	  var_exists = var != 0;
720	  array_exists = var && (array_p (var) || assoc_p (var));
721	  creating_array = flags_on & (att_array|att_assoc);
722#endif
723
724	  if (var == 0)
725	    {
726#if defined (ARRAY_VARS)
727	      if (flags_on & att_assoc)
728		{
729		  var = make_new_assoc_variable (name);
730		  if (var && offset == 0)
731		    VSETATTR (var, att_invisible);
732		}
733	      else if ((flags_on & att_array) || making_array_special)
734		{
735		  var = make_new_array_variable (name);
736		  if (var && offset == 0)
737		    VSETATTR (var, att_invisible);
738		}
739	      else
740#endif
741		{
742		  var = mkglobal ? bind_global_variable (name, (char *)NULL, ASS_FORCE) : bind_variable (name, (char *)NULL, ASS_FORCE);
743		  if (var && offset == 0)
744		    VSETATTR (var, att_invisible);
745		}
746	      if (var == 0)
747		{
748		  /* Has to appear in brackets */
749		  NEXT_VARIABLE ();
750		}
751	      created_var = 1;
752	    }
753	  /* Can't take an existing array variable and make it a nameref */
754	  else if ((array_p (var) || assoc_p (var)) && (flags_on & att_nameref))
755	    {
756	      builtin_error (_("%s: reference variable cannot be an array"), name);
757	      assign_error++;
758	      NEXT_VARIABLE ();
759	    }
760	  else if (nameref_p (var) && (flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0 && offset && valid_nameref_value (value, 1) == 0)
761	    {
762	      builtin_error (_("`%s': invalid variable name for name reference"), value);
763	      any_failed++;
764	      NEXT_VARIABLE ();
765	    }
766	  else if (flags_on & att_nameref)
767	    {
768#if 1
769	      /* Check of offset is to allow an assignment to a nameref var as
770		 part of the declare word to override existing value */
771	      if (nameref_p (var) == 0 && var_isset (var) && offset == 0 && valid_nameref_value (value_cell (var), 0) == 0)
772		{
773		  builtin_error (_("`%s': invalid variable name for name reference"), value_cell (var));
774		  any_failed++;
775		  NEXT_VARIABLE ();
776		}
777#endif
778	      if (readonly_p (var))
779		{
780		  sh_readonly (name);
781		  any_failed++;
782		  NEXT_VARIABLE ();
783		}
784	      /* ksh93 compat: turning on nameref attribute turns off -ilu */
785	      VUNSETATTR (var, att_integer|att_uppercase|att_lowercase|att_capcase);
786	    }
787
788	  /* Cannot use declare +r to turn off readonly attribute. */
789	  if (readonly_p (var) && (flags_off & att_readonly))
790	    {
791	      sh_readonly (name_cell (var));
792	      any_failed++;
793	      NEXT_VARIABLE ();
794	    }
795
796	  /* Cannot use declare to assign value to readonly or noassign
797	     variable. */
798	  if ((readonly_p (var) || noassign_p (var)) && offset)
799	    {
800	      if (readonly_p (var))
801		sh_readonly (name);
802	      assign_error++;
803	      NEXT_VARIABLE ();
804	    }
805
806#if defined (ARRAY_VARS)
807	  /* make declare a[2]=foo as similar to a[2]=foo as possible if
808	     a is already an array or assoc variable. */
809	  if (array_subscript_assignment && array_exists && creating_array == 0)
810	    simple_array_assign = 1;
811	  else if ((making_array_special || creating_array || array_exists) && offset)
812	    {
813	      int vlen;
814	      vlen = STRLEN (value);
815/*itrace("declare_builtin: name = %s value = %s flags = %d", name, value, wflags);*/
816	      if (shell_compatibility_level > 43 && (wflags & W_COMPASSIGN) == 0 &&
817			value[0] == '(' && value[vlen-1] == ')')
818		{
819		  /* The warning is only printed when using compound assignment
820		     to an array variable that doesn't already exist.  We use
821		     creating_array to allow things like
822		     declare -a foo$bar='(abc)' to work. */
823		  if (array_exists == 0 && creating_array == 0)
824		    internal_warning (_("%s: quoted compound array assignment deprecated"), list->word->word);
825		  compound_array_assign = array_exists || creating_array;
826		  simple_array_assign = making_array_special;
827		}
828	      else if (value[0] == '(' && value[vlen-1] == ')' && (shell_compatibility_level < 44 || (wflags & W_COMPASSIGN)))
829		compound_array_assign = 1;
830	      else
831		simple_array_assign = 1;
832	    }
833
834	  /* Cannot use declare +a name or declare +A name to remove an
835	     array variable. */
836	  if (((flags_off & att_array) && array_p (var)) || ((flags_off & att_assoc) && assoc_p (var)))
837	    {
838	      builtin_error (_("%s: cannot destroy array variables in this way"), name);
839	      any_failed++;
840	      NEXT_VARIABLE ();
841	    }
842
843	  if ((flags_on & att_array) && assoc_p (var))
844	    {
845	      builtin_error (_("%s: cannot convert associative to indexed array"), name);
846	      any_failed++;
847	      NEXT_VARIABLE ();
848	    }
849	  if ((flags_on & att_assoc) && array_p (var))
850	    {
851	      builtin_error (_("%s: cannot convert indexed to associative array"), name);
852	      any_failed++;
853	      NEXT_VARIABLE ();
854	    }
855
856	  /* declare -A name[[n]] makes name an associative array variable. */
857	  if (flags_on & att_assoc)
858	    {
859	      if (assoc_p (var) == 0)
860		var = convert_var_to_assoc (var);
861	    }
862	  /* declare -a name[[n]] or declare name[n] makes name an indexed
863	     array variable. */
864	  else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0 && assoc_p (var) == 0)
865	    var = convert_var_to_array (var);
866#endif /* ARRAY_VARS */
867
868	  /* XXX - we note that we are turning on nameref attribute and defer
869	     setting it until the assignment has been made so we don't do an
870	     inadvertent nameref lookup.  Might have to do the same thing for
871	     flags_off&att_nameref. */
872	  /* XXX - ksh93 makes it an error to set a readonly nameref variable
873	     using a single typeset command. */
874	  onref = (flags_on & att_nameref);
875	  flags_on &= ~att_nameref;
876#if defined (ARRAY_VARS)
877	  if (array_p (var) || assoc_p (var)
878		|| (offset && compound_array_assign)
879		|| simple_array_assign)
880	    onref = 0;		/* array variables may not be namerefs */
881#endif
882
883	  /* ksh93 seems to do this */
884	  offref = (flags_off & att_nameref);
885	  flags_off &= ~att_nameref;
886
887	  VSETATTR (var, flags_on);
888	  VUNSETATTR (var, flags_off);
889
890#if defined (ARRAY_VARS)
891	  if (offset && compound_array_assign)
892	    assign_array_var_from_string (var, value, aflags|ASS_FORCE);
893	  else if (simple_array_assign && subscript_start)
894	    {
895	      int local_aflags;
896	      /* declare [-aA] name[N]=value */
897	      *subscript_start = '[';	/* ] */
898	      /* XXX - problem here with appending */
899	      local_aflags = aflags&ASS_APPEND;
900	      local_aflags |= assoc_noexpand ? ASS_NOEXPAND : 0;
901	      var = assign_array_element (name, value, local_aflags);	/* XXX - not aflags */
902	      *subscript_start = '\0';
903	      if (var == 0)	/* some kind of assignment error */
904		{
905		  assign_error++;
906		  flags_on |= onref;
907		  flags_off |= offref;
908		  NEXT_VARIABLE ();
909		}
910	    }
911	  else if (simple_array_assign)
912	    {
913	      /* let bind_{array,assoc}_variable take care of this. */
914	      if (assoc_p (var))
915		bind_assoc_variable (var, name, savestring ("0"), value, aflags|ASS_FORCE);
916	      else
917		bind_array_variable (name, 0, value, aflags|ASS_FORCE);
918	    }
919	  else
920#endif
921	  /* XXX - no ASS_FORCE here */
922	  /* bind_variable_value duplicates the essential internals of
923	     bind_variable() */
924	  if (offset)
925	    {
926	      if (onref || nameref_p (var))
927		aflags |= ASS_NAMEREF;
928	      v = bind_variable_value (var, value, aflags);
929	      if (v == 0 && (onref || nameref_p (var)))
930		{
931		  if (valid_nameref_value (value, 1) == 0)
932		    sh_invalidid (value);
933		  assign_error++;
934		  /* XXX - unset this variable? or leave it as normal var? */
935		  if (created_var)
936		    delete_var (var->name, mkglobal ? global_variables : shell_variables);
937		  flags_on |= onref;		/* undo change from above */
938		  flags_off |= offref;
939		  NEXT_VARIABLE ();
940		}
941	    }
942
943	  /* If we found this variable in the temporary environment, as with
944	     `var=value declare -x var', make sure it is treated identically
945	     to `var=value export var'.  Do the same for `declare -r' and
946	     `readonly'.  Preserve the attributes, except for att_tempvar. */
947	  /* XXX -- should this create a variable in the global scope, or
948	     modify the local variable flags?  ksh93 has it modify the
949	     global scope.
950	     Need to handle case like in set_var_attribute where a temporary
951	     variable is in the same table as the function local vars. */
952	  if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var))
953	    {
954	      SHELL_VAR *tv;
955	      char *tvalue;
956
957	      tv = find_tempenv_variable (var->name);
958	      if (tv)
959		{
960		  tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
961	          tv = bind_variable (var->name, tvalue, 0);
962		  if (tv)
963		    {
964		      tv->attributes |= var->attributes & ~att_tempvar;
965		      if (tv->context > 0)
966			VSETATTR (tv, att_propagate);
967		    }
968	          free (tvalue);
969		}
970	      VSETATTR (var, att_propagate);
971	    }
972	}
973
974      /* Turn on nameref attribute we deferred above. */
975      /* XXX - should we turn on the noassign attribute for consistency with
976	 ksh93 when we turn on the nameref attribute? */
977      VSETATTR (var, onref);
978      flags_on |= onref;
979      VUNSETATTR (var, offref);
980      flags_off |= offref;
981      /* Yuck.  ksh93 compatibility.  XXX - need to investigate more but
982	 definitely happens when turning off nameref attribute on nameref
983	 (see comments above).  Under no circumstances allow this to turn
984	 off readonly attribute on readonly nameref variable. */
985      if (refvar)
986	{
987	  if (flags_off & att_readonly)
988	    flags_off &= ~att_readonly;
989 	  VUNSETATTR (refvar, flags_off);
990	}
991
992      stupidly_hack_special_variables (name);
993
994      NEXT_VARIABLE ();
995    }
996
997  return (assign_error ? EX_BADASSIGN
998		       : ((any_failed == 0) ? EXECUTION_SUCCESS
999  					    : EXECUTION_FAILURE));
1000}
1001