blob: c0b388026e5a5ddef30ad0e2e0cdf40982ff4927 [file] [log] [blame]
Dan Pasanenc6e37862014-10-02 14:08:59 -05001/* declare.c, created from declare.def. */
2#line 22 "./declare.def"
3
4#line 62 "./declare.def"
5
6#line 70 "./declare.def"
7
8#include <config.h>
9
10#if defined (HAVE_UNISTD_H)
11# ifdef _MINIX
12# include <sys/types.h>
13# endif
14# include <unistd.h>
15#endif
16
17#include <stdio.h>
18
19#include "../bashansi.h"
20#include "../bashintl.h"
21
22#include "../shell.h"
23#include "common.h"
24#include "builtext.h"
25#include "bashgetopt.h"
26
27extern int array_needs_making;
28extern int posixly_correct;
29
30static int declare_internal __P((register WORD_LIST *, int));
31
32/* Declare or change variable attributes. */
33int
34declare_builtin (list)
35 register WORD_LIST *list;
36{
37 return (declare_internal (list, 0));
38}
39
40#line 118 "./declare.def"
41int
42local_builtin (list)
43 register WORD_LIST *list;
44{
45 if (variable_context)
46 return (declare_internal (list, 1));
47 else
48 {
49 builtin_error (_("can only be used in a function"));
50 return (EXECUTION_FAILURE);
51 }
52}
53
54#if defined (ARRAY_VARS)
55# define DECLARE_OPTS "+acfgilnprtuxAF"
56#else
57# define DECLARE_OPTS "+cfgilnprtuxF"
58#endif
59
60/* The workhorse function. */
61static int
62declare_internal (list, local_var)
63 register WORD_LIST *list;
64 int local_var;
65{
66 int flags_on, flags_off, *flags;
67 int any_failed, assign_error, pflag, nodefs, opt, mkglobal, onref, offref;
68 char *t, *subscript_start;
69 SHELL_VAR *var, *refvar, *v;
70 FUNCTION_DEF *shell_fn;
71
72 flags_on = flags_off = any_failed = assign_error = pflag = nodefs = mkglobal = 0;
73 refvar = (SHELL_VAR *)NULL;
74 reset_internal_getopt ();
75 while ((opt = internal_getopt (list, DECLARE_OPTS)) != EOF)
76 {
77 flags = list_opttype == '+' ? &flags_off : &flags_on;
78
79 switch (opt)
80 {
81 case 'a':
82#if defined (ARRAY_VARS)
83 *flags |= att_array;
84 break;
85#else
86 builtin_usage ();
87 return (EX_USAGE);
88#endif
89 case 'A':
90#if defined (ARRAY_VARS)
91 *flags |= att_assoc;
92 break;
93#else
94 builtin_usage ();
95 return (EX_USAGE);
96#endif
97 case 'p':
98 if (local_var == 0)
99 pflag++;
100 break;
101 case 'F':
102 nodefs++;
103 *flags |= att_function;
104 break;
105 case 'f':
106 *flags |= att_function;
107 break;
108 case 'g':
109 if (flags == &flags_on)
110 mkglobal = 1;
111 break;
112 case 'i':
113 *flags |= att_integer;
114 break;
115 case 'n':
116 *flags |= att_nameref;
117 break;
118 case 'r':
119 *flags |= att_readonly;
120 break;
121 case 't':
122 *flags |= att_trace;
123 break;
124 case 'x':
125 *flags |= att_exported;
126 array_needs_making = 1;
127 break;
128#if defined (CASEMOD_ATTRS)
129# if defined (CASEMOD_CAPCASE)
130 case 'c':
131 *flags |= att_capcase;
132 if (flags == &flags_on)
133 flags_off |= att_uppercase|att_lowercase;
134 break;
135# endif
136 case 'l':
137 *flags |= att_lowercase;
138 if (flags == &flags_on)
139 flags_off |= att_capcase|att_uppercase;
140 break;
141 case 'u':
142 *flags |= att_uppercase;
143 if (flags == &flags_on)
144 flags_off |= att_capcase|att_lowercase;
145 break;
146#endif /* CASEMOD_ATTRS */
147 default:
148 builtin_usage ();
149 return (EX_USAGE);
150 }
151 }
152
153 list = loptend;
154
155 /* If there are no more arguments left, then we just want to show
156 some variables. */
157 if (list == 0) /* declare -[aAfFirtx] */
158 {
159 /* Show local variables defined at this context level if this is
160 the `local' builtin. */
161 if (local_var)
162 {
163 register SHELL_VAR **vlist;
164 register int i;
165
166 vlist = all_local_variables ();
167
168 if (vlist)
169 {
170 for (i = 0; vlist[i]; i++)
171 print_assignment (vlist[i]);
172
173 free (vlist);
174 }
175 }
176 else if (pflag && (flags_on == 0 || flags_on == att_function))
177 show_all_var_attributes (flags_on == 0, nodefs);
178 else if (flags_on == 0)
179 return (set_builtin ((WORD_LIST *)NULL));
180 else
181 set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
182
183 return (sh_chkwrite (EXECUTION_SUCCESS));
184 }
185
186 if (pflag) /* declare -p [-aAfFirtx] name [name...] */
187 {
188 for (any_failed = 0; list; list = list->next)
189 {
190 if (flags_on & att_function)
191 pflag = show_func_attributes (list->word->word, nodefs);
192 else
193 pflag = show_name_attributes (list->word->word, nodefs);
194 if (pflag)
195 {
196 sh_notfound (list->word->word);
197 any_failed++;
198 }
199 }
200 return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS));
201 }
202
203#define NEXT_VARIABLE() free (name); list = list->next; continue
204
205 /* There are arguments left, so we are making variables. */
206 while (list) /* declare [-aAfFirx] name [name ...] */
207 {
208 char *value, *name;
209 int offset, aflags;
210#if defined (ARRAY_VARS)
211 int making_array_special, compound_array_assign, simple_array_assign;
212#endif
213
214 name = savestring (list->word->word);
215 offset = assignment (name, 0);
216 aflags = 0;
217
218 if (offset) /* declare [-aAfFirx] name=value */
219 {
220 name[offset] = '\0';
221 value = name + offset + 1;
222 if (name[offset - 1] == '+')
223 {
224 aflags |= ASS_APPEND;
225 name[offset - 1] = '\0';
226 }
227 }
228 else
229 value = "";
230
231 /* Do some lexical error checking on the LHS and RHS of the assignment
232 that is specific to nameref variables. */
233 if (flags_on & att_nameref)
234 {
235#if defined (ARRAY_VARIABLES)
236 if (valid_array_reference (name))
237 {
238 builtin_error (_("%s: reference variable cannot be an array"), name);
239 assign_error++;
240 NEXT_VARIABLE ();
241 }
242 else
243#endif
244 /* disallow self references at global scope */
245 if (STREQ (name, value) && variable_context == 0)
246 {
247 builtin_error (_("%s: nameref variable self references not allowed"), name);
248 assign_error++;
249 NEXT_VARIABLE ();
250 }
251 }
252
253#if defined (ARRAY_VARS)
254 compound_array_assign = simple_array_assign = 0;
255 subscript_start = (char *)NULL;
256 if (t = strchr (name, '[')) /* ] */
257 {
258 /* If offset != 0 we have already validated any array reference */
259 if (offset == 0 && valid_array_reference (name) == 0)
260 {
261 sh_invalidid (name);
262 assign_error++;
263 NEXT_VARIABLE ();
264 }
265 subscript_start = t;
266 *t = '\0';
267 making_array_special = 1;
268 }
269 else
270 making_array_special = 0;
271#endif
272
273 /* If we're in posix mode or not looking for a shell function (since
274 shell function names don't have to be valid identifiers when the
275 shell's not in posix mode), check whether or not the argument is a
276 valid, well-formed shell identifier. */
277 if ((posixly_correct || (flags_on & att_function) == 0) && legal_identifier (name) == 0)
278 {
279 sh_invalidid (name);
280 assign_error++;
281 NEXT_VARIABLE ();
282 }
283
284 /* If VARIABLE_CONTEXT has a non-zero value, then we are executing
285 inside of a function. This means we should make local variables,
286 not global ones. */
287
288 /* XXX - this has consequences when we're making a local copy of a
289 variable that was in the temporary environment. Watch out
290 for this. */
291 refvar = (SHELL_VAR *)NULL;
292 if (variable_context && mkglobal == 0 && ((flags_on & att_function) == 0))
293 {
294#if defined (ARRAY_VARS)
295 if (flags_on & att_assoc)
296 var = make_local_assoc_variable (name);
297 else if ((flags_on & att_array) || making_array_special)
298 var = make_local_array_variable (name, making_array_special);
299 else
300#endif
301 var = make_local_variable (name); /* sets att_invisible for new vars */
302 if (var == 0)
303 {
304 any_failed++;
305 NEXT_VARIABLE ();
306 }
307 }
308 else
309 var = (SHELL_VAR *)NULL;
310
311 /* If we are declaring a function, then complain about it in some way.
312 We don't let people make functions by saying `typeset -f foo=bar'. */
313
314 /* There should be a way, however, to let people look at a particular
315 function definition by saying `typeset -f foo'. */
316
317 if (flags_on & att_function)
318 {
319 if (offset) /* declare -f [-rix] foo=bar */
320 {
321 builtin_error (_("cannot use `-f' to make functions"));
322 free (name);
323 return (EXECUTION_FAILURE);
324 }
325 else /* declare -f [-rx] name [name...] */
326 {
327 var = find_function (name);
328
329 if (var)
330 {
331 if (readonly_p (var) && (flags_off & att_readonly))
332 {
333 builtin_error (_("%s: readonly function"), name);
334 any_failed++;
335 NEXT_VARIABLE ();
336 }
337
338 /* declare -[Ff] name [name...] */
339 if (flags_on == att_function && flags_off == 0)
340 {
341#if defined (DEBUGGER)
342 if (nodefs && debugging_mode)
343 {
344 shell_fn = find_function_def (var->name);
345 if (shell_fn)
346 printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file);
347 else
348 printf ("%s\n", var->name);
349 }
350 else
351#endif /* DEBUGGER */
352 {
353 t = nodefs ? var->name
354 : named_function_string (name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL);
355 printf ("%s\n", t);
356 any_failed = sh_chkwrite (any_failed);
357 }
358 }
359 else /* declare -[fF] -[rx] name [name...] */
360 {
361 VSETATTR (var, flags_on);
362 VUNSETATTR (var, flags_off);
363 }
364 }
365 else
366 any_failed++;
367 NEXT_VARIABLE ();
368 }
369 }
370 else /* declare -[aAirx] name [name...] */
371 {
372 /* Non-null if we just created or fetched a local variable. */
373 /* Here's what ksh93 seems to do. If we are modifying an existing
374 nameref variable, we don't follow the nameref chain past the last
375 nameref, and we set the nameref variable's value so future
376 references to that variable will return the value of the variable
377 we're assigning right now. */
378 if (var == 0 && (flags_on & att_nameref))
379 {
380 /* See if we are trying to modify an existing nameref variable */
381 var = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name);
382 if (var && nameref_p (var) == 0)
383 var = 0;
384 }
385 /* However, if we're turning off the nameref attribute on an existing
386 nameref variable, we first follow the nameref chain to the end,
387 modify the value of the variable this nameref variable references,
388 *CHANGING ITS VALUE AS A SIDE EFFECT* then turn off the nameref
389 flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */
390 else if (var == 0 && (flags_off & att_nameref))
391 {
392 /* See if we are trying to modify an existing nameref variable */
393 refvar = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name);
394 if (refvar && nameref_p (refvar) == 0)
395 refvar = 0;
396 if (refvar)
397 var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
398 }
399
400 if (var == 0)
401 var = mkglobal ? find_global_variable (name) : find_variable (name);
402
403 if (var == 0)
404 {
405#if defined (ARRAY_VARS)
406 if (flags_on & att_assoc)
407 {
408 var = make_new_assoc_variable (name);
409 if (offset == 0)
410 VSETATTR (var, att_invisible);
411 }
412 else if ((flags_on & att_array) || making_array_special)
413 {
414 var = make_new_array_variable (name);
415 if (offset == 0)
416 VSETATTR (var, att_invisible);
417 }
418 else
419#endif
420
421 if (offset)
422 var = mkglobal ? bind_global_variable (name, "", 0) : bind_variable (name, "", 0);
423 else
424 {
425 var = mkglobal ? bind_global_variable (name, (char *)NULL, 0) : bind_variable (name, (char *)NULL, 0);
426 VSETATTR (var, att_invisible);
427 }
428 }
429 /* Can't take an existing array variable and make it a nameref */
430 else if ((array_p (var) || assoc_p (var)) && (flags_on & att_nameref))
431 {
432 builtin_error (_("%s: reference variable cannot be an array"), name);
433 assign_error++;
434 NEXT_VARIABLE ();
435 }
436 else if (flags_on & att_nameref)
437 {
438 /* ksh93 compat: turning on nameref attribute turns off -ilu */
439 VUNSETATTR (var, att_integer|att_uppercase|att_lowercase|att_capcase);
440 }
441
442 /* Cannot use declare +r to turn off readonly attribute. */
443 if (readonly_p (var) && (flags_off & att_readonly))
444 {
445 sh_readonly (name);
446 any_failed++;
447 NEXT_VARIABLE ();
448 }
449
450 /* Cannot use declare to assign value to readonly or noassign
451 variable. */
452 if ((readonly_p (var) || noassign_p (var)) && offset)
453 {
454 if (readonly_p (var))
455 sh_readonly (name);
456 assign_error++;
457 NEXT_VARIABLE ();
458 }
459
460#if defined (ARRAY_VARS)
461 if ((making_array_special || (flags_on & (att_array|att_assoc)) || array_p (var) || assoc_p (var)) && offset)
462 {
463 int vlen;
464 vlen = STRLEN (value);
465
466 if (value[0] == '(' && value[vlen-1] == ')')
467 compound_array_assign = 1;
468 else
469 simple_array_assign = 1;
470 }
471
472 /* Cannot use declare +a name or declare +A name to remove an
473 array variable. */
474 if (((flags_off & att_array) && array_p (var)) || ((flags_off & att_assoc) && assoc_p (var)))
475 {
476 builtin_error (_("%s: cannot destroy array variables in this way"), name);
477 any_failed++;
478 NEXT_VARIABLE ();
479 }
480
481 if ((flags_on & att_array) && assoc_p (var))
482 {
483 builtin_error (_("%s: cannot convert associative to indexed array"), name);
484 any_failed++;
485 NEXT_VARIABLE ();
486 }
487 if ((flags_on & att_assoc) && array_p (var))
488 {
489 builtin_error (_("%s: cannot convert indexed to associative array"), name);
490 any_failed++;
491 NEXT_VARIABLE ();
492 }
493
494 /* declare -A name[[n]] makes name an associative array variable. */
495 if (flags_on & att_assoc)
496 {
497 if (assoc_p (var) == 0)
498 var = convert_var_to_assoc (var);
499 }
500 /* declare -a name[[n]] or declare name[n] makes name an indexed
501 array variable. */
502 else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0 && assoc_p (var) == 0)
503 var = convert_var_to_array (var);
504#endif /* ARRAY_VARS */
505
506 /* XXX - we note that we are turning on nameref attribute and defer
507 setting it until the assignment has been made so we don't do an
508 inadvertent nameref lookup. Might have to do the same thing for
509 flags_off&att_nameref. */
510 /* XXX - ksh93 makes it an error to set a readonly nameref variable
511 using a single typeset command. */
512 onref = (flags_on & att_nameref);
513 flags_on &= ~att_nameref;
514#if defined (ARRAY_VARS)
515 if (array_p (var) || assoc_p (var)
516 || (offset && compound_array_assign)
517 || simple_array_assign)
518 onref = 0; /* array variables may not be namerefs */
519#endif
520
521 /* ksh93 seems to do this */
522 offref = (flags_off & att_nameref);
523 flags_off &= ~att_nameref;
524
525 VSETATTR (var, flags_on);
526 VUNSETATTR (var, flags_off);
527
528#if defined (ARRAY_VARS)
529 if (offset && compound_array_assign)
530 assign_array_var_from_string (var, value, aflags);
531 else if (simple_array_assign && subscript_start)
532 {
533 /* declare [-aA] name[N]=value */
534 *subscript_start = '['; /* ] */
535 var = assign_array_element (name, value, 0); /* XXX - not aflags */
536 *subscript_start = '\0';
537 if (var == 0) /* some kind of assignment error */
538 {
539 assign_error++;
540 flags_on |= onref;
541 flags_off |= offref;
542 NEXT_VARIABLE ();
543 }
544 }
545 else if (simple_array_assign)
546 {
547 /* let bind_{array,assoc}_variable take care of this. */
548 if (assoc_p (var))
549 bind_assoc_variable (var, name, savestring ("0"), value, aflags);
550 else
551 bind_array_variable (name, 0, value, aflags);
552 }
553 else
554#endif
555 /* bind_variable_value duplicates the essential internals of
556 bind_variable() */
557 if (offset)
558 {
559 if (onref)
560 aflags |= ASS_NAMEREF;
561 v = bind_variable_value (var, value, aflags);
562 if (v == 0 && onref)
563 {
564 sh_invalidid (value);
565 assign_error++;
566 /* XXX - unset this variable? or leave it as normal var? */
567 delete_var (var->name, mkglobal ? global_variables : shell_variables);
568 NEXT_VARIABLE ();
569 }
570 }
571
572 /* If we found this variable in the temporary environment, as with
573 `var=value declare -x var', make sure it is treated identically
574 to `var=value export var'. Do the same for `declare -r' and
575 `readonly'. Preserve the attributes, except for att_tempvar. */
576 /* XXX -- should this create a variable in the global scope, or
577 modify the local variable flags? ksh93 has it modify the
578 global scope.
579 Need to handle case like in set_var_attribute where a temporary
580 variable is in the same table as the function local vars. */
581 if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var))
582 {
583 SHELL_VAR *tv;
584 char *tvalue;
585
586 tv = find_tempenv_variable (var->name);
587 if (tv)
588 {
589 tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
590 tv = bind_variable (var->name, tvalue, 0);
591 tv->attributes |= var->attributes & ~att_tempvar;
592 if (tv->context > 0)
593 VSETATTR (tv, att_propagate);
594 free (tvalue);
595 }
596 VSETATTR (var, att_propagate);
597 }
598 }
599
600 /* Turn on nameref attribute we deferred above. */
601 /* XXX - should we turn on the noassign attribute for consistency with
602 ksh93 when we turn on the nameref attribute? */
603 VSETATTR (var, onref);
604 flags_on |= onref;
605 VUNSETATTR (var, offref);
606 flags_off |= offref;
607 /* Yuck. ksh93 compatibility */
608 if (refvar)
609 VUNSETATTR (refvar, flags_off);
610
611 stupidly_hack_special_variables (name);
612
613 NEXT_VARIABLE ();
614 }
615
616 return (assign_error ? EX_BADASSIGN
617 : ((any_failed == 0) ? EXECUTION_SUCCESS
618 : EXECUTION_FAILURE));
619}