]> git.ipfire.org Git - thirdparty/bash.git/blob - arrayfunc.c
bash-5.2 distribution sources and documentation
[thirdparty/bash.git] / arrayfunc.c
1 /* arrayfunc.c -- High-level array functions used by other parts of the shell. */
2
3 /* Copyright (C) 2001-2021 Free Software Foundation, Inc.
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
7 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #if defined (ARRAY_VARS)
24
25 #if defined (HAVE_UNISTD_H)
26 # include <unistd.h>
27 #endif
28 #include <stdio.h>
29
30 #include "bashintl.h"
31
32 #include "shell.h"
33 #include "execute_cmd.h"
34 #include "pathexp.h"
35
36 #include "shmbutil.h"
37 #if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
38 # include <mbstr.h> /* mbschr */
39 #endif
40
41 #include "builtins/common.h"
42
43 #ifndef LBRACK
44 # define LBRACK '['
45 # define RBRACK ']'
46 #endif
47
48 /* This variable means to not expand associative array subscripts more than
49 once, when performing variable expansion. */
50 int assoc_expand_once = 0;
51
52 /* Ditto for indexed array subscripts -- currently unused */
53 int array_expand_once = 0;
54
55 static SHELL_VAR *bind_array_var_internal PARAMS((SHELL_VAR *, arrayind_t, char *, char *, int));
56 static SHELL_VAR *assign_array_element_internal PARAMS((SHELL_VAR *, char *, char *, char *, int, char *, int, array_eltstate_t *));
57
58 static void assign_assoc_from_kvlist PARAMS((SHELL_VAR *, WORD_LIST *, HASH_TABLE *, int));
59
60 static char *quote_assign PARAMS((const char *));
61 static void quote_array_assignment_chars PARAMS((WORD_LIST *));
62 static char *quote_compound_array_word PARAMS((char *, int));
63 static char *array_value_internal PARAMS((const char *, int, int, array_eltstate_t *));
64
65 /* Standard error message to use when encountering an invalid array subscript */
66 const char * const bash_badsub_errmsg = N_("bad array subscript");
67
68 /* **************************************************************** */
69 /* */
70 /* Functions to manipulate array variables and perform assignments */
71 /* */
72 /* **************************************************************** */
73
74 /* Convert a shell variable to an array variable. The original value is
75 saved as array[0]. */
76 SHELL_VAR *
77 convert_var_to_array (var)
78 SHELL_VAR *var;
79 {
80 char *oldval;
81 ARRAY *array;
82
83 oldval = value_cell (var);
84 array = array_create ();
85 if (oldval)
86 array_insert (array, 0, oldval);
87
88 FREE (value_cell (var));
89 var_setarray (var, array);
90
91 /* these aren't valid anymore */
92 var->dynamic_value = (sh_var_value_func_t *)NULL;
93 var->assign_func = (sh_var_assign_func_t *)NULL;
94
95 INVALIDATE_EXPORTSTR (var);
96 if (exported_p (var))
97 array_needs_making++;
98
99 VSETATTR (var, att_array);
100 if (oldval)
101 VUNSETATTR (var, att_invisible);
102
103 /* Make sure it's not marked as an associative array any more */
104 VUNSETATTR (var, att_assoc);
105
106 /* Since namerefs can't be array variables, turn off nameref attribute */
107 VUNSETATTR (var, att_nameref);
108
109 return var;
110 }
111
112 /* Convert a shell variable to an array variable. The original value is
113 saved as array[0]. */
114 SHELL_VAR *
115 convert_var_to_assoc (var)
116 SHELL_VAR *var;
117 {
118 char *oldval;
119 HASH_TABLE *hash;
120
121 oldval = value_cell (var);
122 hash = assoc_create (0);
123 if (oldval)
124 assoc_insert (hash, savestring ("0"), oldval);
125
126 FREE (value_cell (var));
127 var_setassoc (var, hash);
128
129 /* these aren't valid anymore */
130 var->dynamic_value = (sh_var_value_func_t *)NULL;
131 var->assign_func = (sh_var_assign_func_t *)NULL;
132
133 INVALIDATE_EXPORTSTR (var);
134 if (exported_p (var))
135 array_needs_making++;
136
137 VSETATTR (var, att_assoc);
138 if (oldval)
139 VUNSETATTR (var, att_invisible);
140
141 /* Make sure it's not marked as an indexed array any more */
142 VUNSETATTR (var, att_array);
143
144 /* Since namerefs can't be array variables, turn off nameref attribute */
145 VUNSETATTR (var, att_nameref);
146
147 return var;
148 }
149
150 char *
151 make_array_variable_value (entry, ind, key, value, flags)
152 SHELL_VAR *entry;
153 arrayind_t ind;
154 char *key;
155 char *value;
156 int flags;
157 {
158 SHELL_VAR *dentry;
159 char *newval;
160
161 /* If we're appending, we need the old value of the array reference, so
162 fake out make_variable_value with a dummy SHELL_VAR */
163 if (flags & ASS_APPEND)
164 {
165 dentry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
166 dentry->name = savestring (entry->name);
167 if (assoc_p (entry))
168 newval = assoc_reference (assoc_cell (entry), key);
169 else
170 newval = array_reference (array_cell (entry), ind);
171 if (newval)
172 dentry->value = savestring (newval);
173 else
174 {
175 dentry->value = (char *)xmalloc (1);
176 dentry->value[0] = '\0';
177 }
178 dentry->exportstr = 0;
179 dentry->attributes = entry->attributes & ~(att_array|att_assoc|att_exported);
180 /* Leave the rest of the members uninitialized; the code doesn't look
181 at them. */
182 newval = make_variable_value (dentry, value, flags);
183 dispose_variable (dentry);
184 }
185 else
186 newval = make_variable_value (entry, value, flags);
187
188 return newval;
189 }
190
191 /* Assign HASH[KEY]=VALUE according to FLAGS. ENTRY is an associative array
192 variable; HASH is the hash table to assign into. HASH may or may not be
193 the hash table associated with ENTRY; if it's not, the caller takes care
194 of it.
195 XXX - make sure that any dynamic associative array variables recreate the
196 hash table on each assignment. BASH_CMDS and BASH_ALIASES already do this */
197 static SHELL_VAR *
198 bind_assoc_var_internal (entry, hash, key, value, flags)
199 SHELL_VAR *entry;
200 HASH_TABLE *hash;
201 char *key;
202 char *value;
203 int flags;
204 {
205 char *newval;
206
207 /* Use the existing array contents to expand the value */
208 newval = make_array_variable_value (entry, 0, key, value, flags);
209
210 if (entry->assign_func)
211 (*entry->assign_func) (entry, newval, 0, key);
212 else
213 assoc_insert (hash, key, newval);
214
215 FREE (newval);
216
217 VUNSETATTR (entry, att_invisible); /* no longer invisible */
218
219 /* check mark_modified_variables if we ever want to export array vars */
220 return (entry);
221 }
222
223 /* Perform ENTRY[IND]=VALUE or ENTRY[KEY]=VALUE. This is not called for every
224 assignment to an associative array; see assign_compound_array_list below. */
225 static SHELL_VAR *
226 bind_array_var_internal (entry, ind, key, value, flags)
227 SHELL_VAR *entry;
228 arrayind_t ind;
229 char *key;
230 char *value;
231 int flags;
232 {
233 char *newval;
234
235 newval = make_array_variable_value (entry, ind, key, value, flags);
236
237 if (entry->assign_func)
238 (*entry->assign_func) (entry, newval, ind, key);
239 else if (assoc_p (entry))
240 assoc_insert (assoc_cell (entry), key, newval);
241 else
242 array_insert (array_cell (entry), ind, newval);
243 FREE (newval);
244
245 VUNSETATTR (entry, att_invisible); /* no longer invisible */
246
247 /* check mark_modified_variables if we ever want to export array vars */
248 return (entry);
249 }
250
251 /* Perform an array assignment name[ind]=value. If NAME already exists and
252 is not an array, and IND is 0, perform name=value instead. If NAME exists
253 and is not an array, and IND is not 0, convert it into an array with the
254 existing value as name[0].
255
256 If NAME does not exist, just create an array variable, no matter what
257 IND's value may be. */
258 SHELL_VAR *
259 bind_array_variable (name, ind, value, flags)
260 char *name;
261 arrayind_t ind;
262 char *value;
263 int flags;
264 {
265 SHELL_VAR *entry;
266
267 entry = find_shell_variable (name);
268
269 if (entry == (SHELL_VAR *) 0)
270 {
271 /* Is NAME a nameref variable that points to an unset variable? */
272 entry = find_variable_nameref_for_create (name, 0);
273 if (entry == INVALID_NAMEREF_VALUE)
274 return ((SHELL_VAR *)0);
275 if (entry && nameref_p (entry))
276 entry = make_new_array_variable (nameref_cell (entry));
277 }
278 if (entry == (SHELL_VAR *) 0)
279 entry = make_new_array_variable (name);
280 else if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry))
281 {
282 if (readonly_p (entry))
283 err_readonly (name);
284 return (entry);
285 }
286 else if (array_p (entry) == 0)
287 entry = convert_var_to_array (entry);
288
289 /* ENTRY is an array variable, and ARRAY points to the value. */
290 return (bind_array_var_internal (entry, ind, 0, value, flags));
291 }
292
293 SHELL_VAR *
294 bind_array_element (entry, ind, value, flags)
295 SHELL_VAR *entry;
296 arrayind_t ind;
297 char *value;
298 int flags;
299 {
300 return (bind_array_var_internal (entry, ind, 0, value, flags));
301 }
302
303 SHELL_VAR *
304 bind_assoc_variable (entry, name, key, value, flags)
305 SHELL_VAR *entry;
306 char *name;
307 char *key;
308 char *value;
309 int flags;
310 {
311 if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry))
312 {
313 if (readonly_p (entry))
314 err_readonly (name);
315 return (entry);
316 }
317
318 return (bind_assoc_var_internal (entry, assoc_cell (entry), key, value, flags));
319 }
320
321 inline void
322 init_eltstate (array_eltstate_t *estatep)
323 {
324 if (estatep)
325 {
326 estatep->type = ARRAY_INVALID;
327 estatep->subtype = 0;
328 estatep->key = estatep->value = 0;
329 estatep->ind = INTMAX_MIN;
330 }
331 }
332
333 inline void
334 flush_eltstate (array_eltstate_t *estatep)
335 {
336 if (estatep)
337 FREE (estatep->key);
338 }
339
340 /* Parse NAME, a lhs of an assignment statement of the form v[s], and
341 assign VALUE to that array element by calling bind_array_variable().
342 Flags are ASS_ assignment flags */
343 SHELL_VAR *
344 assign_array_element (name, value, flags, estatep)
345 char *name, *value;
346 int flags;
347 array_eltstate_t *estatep;
348 {
349 char *sub, *vname;
350 int sublen, isassoc, avflags;
351 SHELL_VAR *entry;
352
353 avflags = 0;
354 if (flags & ASS_NOEXPAND)
355 avflags |= AV_NOEXPAND;
356 if (flags & ASS_ONEWORD)
357 avflags |= AV_ONEWORD;
358 vname = array_variable_name (name, avflags, &sub, &sublen);
359
360 if (vname == 0)
361 return ((SHELL_VAR *)NULL);
362
363 entry = find_variable (vname);
364 isassoc = entry && assoc_p (entry);
365
366 /* We don't allow assignment to `*' or `@' associative array keys if the
367 caller hasn't told us the subscript has already been expanded
368 (ASS_NOEXPAND). If the caller has explicitly told us it's ok
369 (ASS_ALLOWALLSUB) we allow it. */
370 if (((isassoc == 0 || (flags & (ASS_NOEXPAND|ASS_ALLOWALLSUB)) == 0) &&
371 (ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']')) ||
372 (sublen <= 1) ||
373 (sub[sublen] != '\0')) /* sanity check */
374 {
375 free (vname);
376 err_badarraysub (name);
377 return ((SHELL_VAR *)NULL);
378 }
379
380 entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags, estatep);
381
382 #if ARRAY_EXPORT
383 if (entry && exported_p (entry))
384 {
385 INVALIDATE_EXPORTSTR (entry);
386 array_needs_making = 1;
387 }
388 #endif
389
390 free (vname);
391 return entry;
392 }
393
394 static SHELL_VAR *
395 assign_array_element_internal (entry, name, vname, sub, sublen, value, flags, estatep)
396 SHELL_VAR *entry;
397 char *name; /* only used for error messages */
398 char *vname;
399 char *sub;
400 int sublen;
401 char *value;
402 int flags;
403 array_eltstate_t *estatep;
404 {
405 char *akey, *nkey;
406 arrayind_t ind;
407 char *newval;
408
409 /* rely on the caller to initialize estatep */
410
411 if (entry && assoc_p (entry))
412 {
413 sub[sublen-1] = '\0';
414 if ((flags & ASS_NOEXPAND) == 0)
415 akey = expand_subscript_string (sub, 0); /* [ */
416 else
417 akey = savestring (sub);
418 sub[sublen-1] = ']';
419 if (akey == 0 || *akey == 0)
420 {
421 err_badarraysub (name);
422 FREE (akey);
423 return ((SHELL_VAR *)NULL);
424 }
425 if (estatep)
426 nkey = savestring (akey); /* assoc_insert/assoc_replace frees akey */
427 entry = bind_assoc_variable (entry, vname, akey, value, flags);
428 if (estatep)
429 {
430 estatep->type = ARRAY_ASSOC;
431 estatep->key = nkey;
432 estatep->value = entry ? assoc_reference (assoc_cell (entry), nkey) : 0;
433 }
434 }
435 else
436 {
437 ind = array_expand_index (entry, sub, sublen, 0);
438 /* negative subscripts to indexed arrays count back from end */
439 if (entry && ind < 0)
440 ind = (array_p (entry) ? array_max_index (array_cell (entry)) : 0) + 1 + ind;
441 if (ind < 0)
442 {
443 err_badarraysub (name);
444 return ((SHELL_VAR *)NULL);
445 }
446 entry = bind_array_variable (vname, ind, value, flags);
447 if (estatep)
448 {
449 estatep->type = ARRAY_INDEXED;
450 estatep->ind = ind;
451 estatep->value = entry ? array_reference (array_cell (entry), ind) : 0;
452 }
453 }
454
455 return (entry);
456 }
457
458 /* Find the array variable corresponding to NAME. If there is no variable,
459 create a new array variable. If the variable exists but is not an array,
460 convert it to an indexed array. If FLAGS&1 is non-zero, an existing
461 variable is checked for the readonly or noassign attribute in preparation
462 for assignment (e.g., by the `read' builtin). If FLAGS&2 is non-zero, we
463 create an associative array. */
464 SHELL_VAR *
465 find_or_make_array_variable (name, flags)
466 char *name;
467 int flags;
468 {
469 SHELL_VAR *var;
470
471 var = find_variable (name);
472 if (var == 0)
473 {
474 /* See if we have a nameref pointing to a variable that hasn't been
475 created yet. */
476 var = find_variable_last_nameref (name, 1);
477 if (var && nameref_p (var) && invisible_p (var))
478 {
479 internal_warning (_("%s: removing nameref attribute"), name);
480 VUNSETATTR (var, att_nameref);
481 }
482 if (var && nameref_p (var))
483 {
484 if (valid_nameref_value (nameref_cell (var), 2) == 0)
485 {
486 sh_invalidid (nameref_cell (var));
487 return ((SHELL_VAR *)NULL);
488 }
489 var = (flags & 2) ? make_new_assoc_variable (nameref_cell (var)) : make_new_array_variable (nameref_cell (var));
490 }
491 }
492
493 if (var == 0)
494 var = (flags & 2) ? make_new_assoc_variable (name) : make_new_array_variable (name);
495 else if ((flags & 1) && (readonly_p (var) || noassign_p (var)))
496 {
497 if (readonly_p (var))
498 err_readonly (name);
499 return ((SHELL_VAR *)NULL);
500 }
501 else if ((flags & 2) && array_p (var))
502 {
503 set_exit_status (EXECUTION_FAILURE);
504 report_error (_("%s: cannot convert indexed to associative array"), name);
505 return ((SHELL_VAR *)NULL);
506 }
507 else if (flags & 2)
508 var = assoc_p (var) ? var : convert_var_to_assoc (var);
509 else if (array_p (var) == 0 && assoc_p (var) == 0)
510 var = convert_var_to_array (var);
511
512 return (var);
513 }
514
515 /* Perform a compound assignment statement for array NAME, where VALUE is
516 the text between the parens: NAME=( VALUE ) */
517 SHELL_VAR *
518 assign_array_from_string (name, value, flags)
519 char *name, *value;
520 int flags;
521 {
522 SHELL_VAR *var;
523 int vflags;
524
525 vflags = 1;
526 if (flags & ASS_MKASSOC)
527 vflags |= 2;
528
529 var = find_or_make_array_variable (name, vflags);
530 if (var == 0)
531 return ((SHELL_VAR *)NULL);
532
533 return (assign_array_var_from_string (var, value, flags));
534 }
535
536 /* Sequentially assign the indices of indexed array variable VAR from the
537 words in LIST. */
538 SHELL_VAR *
539 assign_array_var_from_word_list (var, list, flags)
540 SHELL_VAR *var;
541 WORD_LIST *list;
542 int flags;
543 {
544 register arrayind_t i;
545 register WORD_LIST *l;
546 ARRAY *a;
547
548 a = array_cell (var);
549 i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
550
551 for (l = list; l; l = l->next, i++)
552 bind_array_var_internal (var, i, 0, l->word->word, flags & ~ASS_APPEND);
553
554 VUNSETATTR (var, att_invisible); /* no longer invisible */
555
556 return var;
557 }
558
559 WORD_LIST *
560 expand_compound_array_assignment (var, value, flags)
561 SHELL_VAR *var;
562 char *value;
563 int flags;
564 {
565 WORD_LIST *list, *nlist;
566 char *val;
567 int ni;
568
569 /* This condition is true when invoked from the declare builtin with a
570 command like
571 declare -a d='([1]="" [2]="bdef" [5]="hello world" "test")' */
572 if (*value == '(') /*)*/
573 {
574 ni = 1;
575 val = extract_array_assignment_list (value, &ni);
576 if (val == 0)
577 return (WORD_LIST *)NULL;
578 }
579 else
580 val = value;
581
582 /* Expand the value string into a list of words, performing all the
583 shell expansions including pathname generation and word splitting. */
584 /* First we split the string on whitespace, using the shell parser
585 (ksh93 seems to do this). */
586 /* XXX - this needs a rethink, maybe use split_at_delims */
587 list = parse_string_to_word_list (val, 1, "array assign");
588
589 /* If the parser has quoted CTLESC and CTNLNUL with CTLESC in unquoted
590 words, we need to remove those here because the code below assumes
591 they are there because they exist in the original word. */
592 /* XXX - if we rethink parse_string_to_word_list above, change this. */
593 for (nlist = list; nlist; nlist = nlist->next)
594 if ((nlist->word->flags & W_QUOTED) == 0)
595 remove_quoted_escapes (nlist->word->word);
596
597 /* Note that we defer expansion of the assignment statements for associative
598 arrays here, so we don't have to scan the subscript and find the ending
599 bracket twice. See the caller below. */
600 if (var && assoc_p (var))
601 {
602 if (val != value)
603 free (val);
604 return list;
605 }
606
607 /* If we're using [subscript]=value, we need to quote each [ and ] to
608 prevent unwanted filename expansion. This doesn't need to be done
609 for associative array expansion, since that uses a different expansion
610 function (see assign_compound_array_list below). */
611 if (list)
612 quote_array_assignment_chars (list);
613
614 /* Now that we've split it, perform the shell expansions on each
615 word in the list. */
616 nlist = list ? expand_words_no_vars (list) : (WORD_LIST *)NULL;
617
618 dispose_words (list);
619
620 if (val != value)
621 free (val);
622
623 return nlist;
624 }
625
626 #if ASSOC_KVPAIR_ASSIGNMENT
627 static void
628 assign_assoc_from_kvlist (var, nlist, h, flags)
629 SHELL_VAR *var;
630 WORD_LIST *nlist;
631 HASH_TABLE *h;
632 int flags;
633 {
634 WORD_LIST *list;
635 char *akey, *aval, *k, *v;
636
637 for (list = nlist; list; list = list->next)
638 {
639 k = list->word->word;
640 v = list->next ? list->next->word->word : 0;
641
642 if (list->next)
643 list = list->next;
644
645 akey = expand_subscript_string (k, 0);
646 if (akey == 0 || *akey == 0)
647 {
648 err_badarraysub (k);
649 FREE (akey);
650 continue;
651 }
652
653 aval = expand_subscript_string (v, 0);
654 if (aval == 0)
655 {
656 aval = (char *)xmalloc (1);
657 aval[0] = '\0'; /* like do_assignment_internal */
658 }
659
660 bind_assoc_var_internal (var, h, akey, aval, flags);
661 free (aval);
662 }
663 }
664
665 /* Return non-zero if L appears to be a key-value pair associative array
666 compound assignment. */
667 int
668 kvpair_assignment_p (l)
669 WORD_LIST *l;
670 {
671 return (l && (l->word->flags & W_ASSIGNMENT) == 0 && l->word->word[0] != '['); /*]*/
672 }
673
674 char *
675 expand_and_quote_kvpair_word (w)
676 char *w;
677 {
678 char *r, *s, *t;
679
680 t = w ? expand_subscript_string (w, 0) : 0;
681 s = (t && strchr (t, CTLESC)) ? quote_escapes (t) : t;
682 r = sh_single_quote (s ? s : "");
683 if (s != t)
684 free (s);
685 free (t);
686 return r;
687 }
688 #endif
689
690 /* Callers ensure that VAR is not NULL. Associative array assignments have not
691 been expanded when this is called, or have been expanded once and single-
692 quoted, so we don't have to scan through an unquoted expanded subscript to
693 find the ending bracket; indexed array assignments have been expanded and
694 possibly single-quoted to prevent further expansion.
695
696 If this is an associative array, we perform the assignments into NHASH and
697 set NHASH to be the value of VAR after processing the assignments in NLIST */
698 void
699 assign_compound_array_list (var, nlist, flags)
700 SHELL_VAR *var;
701 WORD_LIST *nlist;
702 int flags;
703 {
704 ARRAY *a;
705 HASH_TABLE *h, *nhash;
706 WORD_LIST *list;
707 char *w, *val, *nval, *savecmd;
708 int len, iflags, free_val;
709 arrayind_t ind, last_ind;
710 char *akey;
711
712 a = (var && array_p (var)) ? array_cell (var) : (ARRAY *)0;
713 nhash = h = (var && assoc_p (var)) ? assoc_cell (var) : (HASH_TABLE *)0;
714
715 akey = (char *)0;
716 ind = 0;
717
718 /* Now that we are ready to assign values to the array, kill the existing
719 value. */
720 if ((flags & ASS_APPEND) == 0)
721 {
722 if (a && array_p (var))
723 array_flush (a);
724 else if (h && assoc_p (var))
725 nhash = assoc_create (h->nbuckets);
726 }
727
728 last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0;
729
730 #if ASSOC_KVPAIR_ASSIGNMENT
731 if (assoc_p (var) && kvpair_assignment_p (nlist))
732 {
733 iflags = flags & ~ASS_APPEND;
734 assign_assoc_from_kvlist (var, nlist, nhash, iflags);
735 if (nhash && nhash != h)
736 {
737 h = assoc_cell (var);
738 var_setassoc (var, nhash);
739 assoc_dispose (h);
740 }
741 return;
742 }
743 #endif
744
745 for (list = nlist; list; list = list->next)
746 {
747 /* Don't allow var+=(values) to make assignments in VALUES append to
748 existing values by default. */
749 iflags = flags & ~ASS_APPEND;
750 w = list->word->word;
751
752 /* We have a word of the form [ind]=value */
753 if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
754 {
755 /* Don't have to handle embedded quotes specially any more, since
756 associative array subscripts have not been expanded yet (see
757 above). */
758 len = skipsubscript (w, 0, 0);
759
760 /* XXX - changes for `+=' */
761 if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
762 {
763 if (assoc_p (var))
764 {
765 err_badarraysub (w);
766 continue;
767 }
768 nval = make_variable_value (var, w, flags);
769 if (var->assign_func)
770 (*var->assign_func) (var, nval, last_ind, 0);
771 else
772 array_insert (a, last_ind, nval);
773 FREE (nval);
774 last_ind++;
775 continue;
776 }
777
778 if (len == 1)
779 {
780 err_badarraysub (w);
781 continue;
782 }
783
784 if (ALL_ELEMENT_SUB (w[1]) && len == 2 && array_p (var))
785 {
786 set_exit_status (EXECUTION_FAILURE);
787 report_error (_("%s: cannot assign to non-numeric index"), w);
788 continue;
789 }
790
791 if (array_p (var))
792 {
793 ind = array_expand_index (var, w + 1, len, 0);
794 /* negative subscripts to indexed arrays count back from end */
795 if (ind < 0)
796 ind = array_max_index (array_cell (var)) + 1 + ind;
797 if (ind < 0)
798 {
799 err_badarraysub (w);
800 continue;
801 }
802
803 last_ind = ind;
804 }
805 else if (assoc_p (var))
806 {
807 /* This is not performed above, see expand_compound_array_assignment */
808 w[len] = '\0'; /*[*/
809 akey = expand_subscript_string (w+1, 0);
810 w[len] = ']';
811 /* And we need to expand the value also, see below */
812 if (akey == 0 || *akey == 0)
813 {
814 err_badarraysub (w);
815 FREE (akey);
816 continue;
817 }
818 }
819
820 /* XXX - changes for `+=' -- just accept the syntax. ksh93 doesn't do this */
821 if (w[len + 1] == '+' && w[len + 2] == '=')
822 {
823 iflags |= ASS_APPEND;
824 val = w + len + 3;
825 }
826 else
827 val = w + len + 2;
828 }
829 else if (assoc_p (var))
830 {
831 set_exit_status (EXECUTION_FAILURE);
832 report_error (_("%s: %s: must use subscript when assigning associative array"), var->name, w);
833 continue;
834 }
835 else /* No [ind]=value, just a stray `=' */
836 {
837 ind = last_ind;
838 val = w;
839 }
840
841 free_val = 0;
842 /* See above; we need to expand the value here */
843 if (assoc_p (var))
844 {
845 val = expand_subscript_string (val, 0);
846 if (val == 0)
847 {
848 val = (char *)xmalloc (1);
849 val[0] = '\0'; /* like do_assignment_internal */
850 }
851 free_val = 1;
852 }
853
854 savecmd = this_command_name;
855 if (integer_p (var))
856 this_command_name = (char *)NULL; /* no command name for errors */
857 if (assoc_p (var))
858 bind_assoc_var_internal (var, nhash, akey, val, iflags);
859 else
860 bind_array_var_internal (var, ind, akey, val, iflags);
861 last_ind++;
862 this_command_name = savecmd;
863
864 if (free_val)
865 free (val);
866 }
867
868 if (assoc_p (var) && nhash && nhash != h)
869 {
870 h = assoc_cell (var);
871 var_setassoc (var, nhash);
872 assoc_dispose (h);
873 }
874 }
875
876 /* Perform a compound array assignment: VAR->name=( VALUE ). The
877 VALUE has already had the parentheses stripped. */
878 SHELL_VAR *
879 assign_array_var_from_string (var, value, flags)
880 SHELL_VAR *var;
881 char *value;
882 int flags;
883 {
884 WORD_LIST *nlist;
885
886 if (value == 0)
887 return var;
888
889 nlist = expand_compound_array_assignment (var, value, flags);
890 assign_compound_array_list (var, nlist, flags);
891
892 if (nlist)
893 dispose_words (nlist);
894
895 if (var)
896 VUNSETATTR (var, att_invisible); /* no longer invisible */
897
898 return (var);
899 }
900
901 /* Quote globbing chars and characters in $IFS before the `=' in an assignment
902 statement (usually a compound array assignment) to protect them from
903 unwanted filename expansion or word splitting. */
904 static char *
905 quote_assign (string)
906 const char *string;
907 {
908 size_t slen;
909 int saw_eq;
910 char *temp, *t, *subs;
911 const char *s, *send;
912 int ss, se;
913 DECLARE_MBSTATE;
914
915 slen = strlen (string);
916 send = string + slen;
917
918 t = temp = (char *)xmalloc (slen * 2 + 1);
919 saw_eq = 0;
920 for (s = string; *s; )
921 {
922 if (*s == '=')
923 saw_eq = 1;
924 if (saw_eq == 0 && *s == '[') /* looks like a subscript */
925 {
926 ss = s - string;
927 se = skipsubscript (string, ss, 0);
928 subs = substring (s, ss, se);
929 *t++ = '\\';
930 strcpy (t, subs);
931 t += se - ss;
932 *t++ = '\\';
933 *t++ = ']';
934 s += se + 1;
935 free (subs);
936 continue;
937 }
938 if (saw_eq == 0 && (glob_char_p (s) || isifs (*s)))
939 *t++ = '\\';
940
941 COPY_CHAR_P (t, s, send);
942 }
943 *t = '\0';
944 return temp;
945 }
946
947 /* Take a word W of the form [IND]=VALUE and transform it to ['IND']='VALUE'
948 to prevent further expansion. This is called for compound assignments to
949 indexed arrays. W has already undergone word expansions. If W has no [IND]=,
950 just single-quote and return it. */
951 static char *
952 quote_compound_array_word (w, type)
953 char *w;
954 int type;
955 {
956 char *nword, *sub, *value, *t;
957 int ind, wlen, i;
958
959 if (w[0] != LBRACK)
960 return (sh_single_quote (w)); /* XXX - quote CTLESC */
961 ind = skipsubscript (w, 0, 0);
962 if (w[ind] != RBRACK)
963 return (sh_single_quote (w)); /* XXX - quote CTLESC */
964
965 wlen = strlen (w);
966 w[ind] = '\0';
967 t = (strchr (w+1, CTLESC)) ? quote_escapes (w+1) : w+1;
968 sub = sh_single_quote (t);
969 if (t != w+1)
970 free (t);
971 w[ind] = RBRACK;
972
973 nword = xmalloc (wlen * 4 + 5); /* wlen*4 is max single quoted length */
974 nword[0] = LBRACK;
975 i = STRLEN (sub);
976 memcpy (nword+1, sub, i);
977 free (sub);
978 i++; /* accommodate the opening LBRACK */
979 nword[i++] = w[ind++]; /* RBRACK */
980 if (w[ind] == '+')
981 nword[i++] = w[ind++];
982 nword[i++] = w[ind++];
983 t = (strchr (w+ind, CTLESC)) ? quote_escapes (w+ind) : w+ind;
984 value = sh_single_quote (t);
985 if (t != w+ind)
986 free (t);
987 strcpy (nword + i, value);
988
989 return nword;
990 }
991
992 /* Expand the key and value in W, which is of the form [KEY]=VALUE, and
993 reconstruct W with the expanded and single-quoted version:
994 ['expanded-key']='expanded-value'. If there is no [KEY]=, single-quote the
995 word and return it. Very similar to previous function, but does not assume
996 W has already been expanded, and expands the KEY and VALUE separately.
997 Used for compound assignments to associative arrays that are arguments to
998 declaration builtins (declare -A a=( list )). */
999 char *
1000 expand_and_quote_assoc_word (w, type)
1001 char *w;
1002 int type;
1003 {
1004 char *nword, *key, *value, *s, *t;
1005 int ind, wlen, i;
1006
1007 if (w[0] != LBRACK)
1008 return (sh_single_quote (w)); /* XXX - quote_escapes */
1009 ind = skipsubscript (w, 0, 0);
1010 if (w[ind] != RBRACK)
1011 return (sh_single_quote (w)); /* XXX - quote_escapes */
1012
1013 w[ind] = '\0';
1014 t = expand_subscript_string (w+1, 0);
1015 s = (t && strchr (t, CTLESC)) ? quote_escapes (t) : t;
1016 key = sh_single_quote (s ? s : "");
1017 if (s != t)
1018 free (s);
1019 w[ind] = RBRACK;
1020 free (t);
1021
1022 wlen = STRLEN (key);
1023 nword = xmalloc (wlen + 5);
1024 nword[0] = LBRACK;
1025 memcpy (nword+1, key, wlen);
1026 i = wlen + 1; /* accommodate the opening LBRACK */
1027
1028 nword[i++] = w[ind++]; /* RBRACK */
1029 if (w[ind] == '+')
1030 nword[i++] = w[ind++];
1031 nword[i++] = w[ind++];
1032
1033 t = expand_subscript_string (w+ind, 0);
1034 s = (t && strchr (t, CTLESC)) ? quote_escapes (t) : t;
1035 value = sh_single_quote (s ? s : "");
1036 if (s != t)
1037 free (s);
1038 free (t);
1039 nword = xrealloc (nword, wlen + 5 + STRLEN (value));
1040 strcpy (nword + i, value);
1041
1042 free (key);
1043 free (value);
1044
1045 return nword;
1046 }
1047
1048 /* For each word in a compound array assignment, if the word looks like
1049 [ind]=value, single-quote ind and value, but leave the brackets and
1050 the = sign (and any `+') alone. If it's not an assignment, just single-
1051 quote the word. This is used for indexed arrays. */
1052 void
1053 quote_compound_array_list (list, type)
1054 WORD_LIST *list;
1055 int type;
1056 {
1057 char *s, *t;
1058 WORD_LIST *l;
1059
1060 for (l = list; l; l = l->next)
1061 {
1062 if (l->word == 0 || l->word->word == 0)
1063 continue; /* should not happen, but just in case... */
1064 if ((l->word->flags & W_ASSIGNMENT) == 0)
1065 {
1066 s = (strchr (l->word->word, CTLESC)) ? quote_escapes (l->word->word) : l->word->word;
1067 t = sh_single_quote (s);
1068 if (s != l->word->word)
1069 free (s);
1070 }
1071 else
1072 t = quote_compound_array_word (l->word->word, type);
1073 free (l->word->word);
1074 l->word->word = t;
1075 }
1076 }
1077
1078 /* For each word in a compound array assignment, if the word looks like
1079 [ind]=value, quote globbing chars and characters in $IFS before the `='. */
1080 static void
1081 quote_array_assignment_chars (list)
1082 WORD_LIST *list;
1083 {
1084 char *nword;
1085 WORD_LIST *l;
1086
1087 for (l = list; l; l = l->next)
1088 {
1089 if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
1090 continue; /* should not happen, but just in case... */
1091 /* Don't bother if it hasn't been recognized as an assignment or
1092 doesn't look like [ind]=value */
1093 if ((l->word->flags & W_ASSIGNMENT) == 0)
1094 continue;
1095 if (l->word->word[0] != '[' || mbschr (l->word->word, '=') == 0) /* ] */
1096 continue;
1097
1098 nword = quote_assign (l->word->word);
1099 free (l->word->word);
1100 l->word->word = nword;
1101 l->word->flags |= W_NOGLOB; /* XXX - W_NOSPLIT also? */
1102 }
1103 }
1104
1105 /* skipsubscript moved to subst.c to use private functions. 2009/02/24. */
1106
1107 /* This function is called with SUB pointing to just after the beginning
1108 `[' of an array subscript and removes the array element to which SUB
1109 expands from array VAR. A subscript of `*' or `@' unsets the array. */
1110 /* If FLAGS&1 (VA_NOEXPAND) we don't expand the subscript; we just use it
1111 as-is. If FLAGS&VA_ONEWORD, we don't try to use skipsubscript to parse
1112 the subscript, we just assume the subscript ends with a close bracket,
1113 if one is present, and use what's inside the brackets. */
1114 int
1115 unbind_array_element (var, sub, flags)
1116 SHELL_VAR *var;
1117 char *sub;
1118 int flags;
1119 {
1120 arrayind_t ind;
1121 char *akey;
1122 ARRAY_ELEMENT *ae;
1123
1124 /* Assume that the caller (unset_builtin) passes us a null-terminated SUB,
1125 so we don't have to use VA_ONEWORD or parse the subscript again with
1126 skipsubscript(). */
1127
1128 if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0)
1129 {
1130 if (array_p (var) || assoc_p (var))
1131 {
1132 if (flags & VA_ALLOWALL)
1133 {
1134 unbind_variable (var->name); /* XXX -- {array,assoc}_flush ? */
1135 return (0);
1136 }
1137 /* otherwise we fall through and try to unset element `@' or `*' */
1138 }
1139 else
1140 return -2; /* don't allow this to unset scalar variables */
1141 }
1142
1143 if (assoc_p (var))
1144 {
1145 akey = (flags & VA_NOEXPAND) ? sub : expand_subscript_string (sub, 0);
1146 if (akey == 0 || *akey == 0)
1147 {
1148 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
1149 FREE (akey);
1150 return -1;
1151 }
1152 assoc_remove (assoc_cell (var), akey);
1153 if (akey != sub)
1154 free (akey);
1155 }
1156 else if (array_p (var))
1157 {
1158 if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0)
1159 {
1160 /* We can go several ways here:
1161 1) remove the array (backwards compatible)
1162 2) empty the array (new behavior)
1163 3) do nothing; treat the `@' or `*' as an expression and throw
1164 an error
1165 */
1166 /* Behavior 1 */
1167 if (shell_compatibility_level <= 51)
1168 {
1169 unbind_variable (name_cell (var));
1170 return 0;
1171 }
1172 else /* Behavior 2 */
1173 {
1174 array_flush (array_cell (var));
1175 return 0;
1176 }
1177 /* Fall through for behavior 3 */
1178 }
1179 ind = array_expand_index (var, sub, strlen (sub) + 1, 0);
1180 /* negative subscripts to indexed arrays count back from end */
1181 if (ind < 0)
1182 ind = array_max_index (array_cell (var)) + 1 + ind;
1183 if (ind < 0)
1184 {
1185 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
1186 return -1;
1187 }
1188 ae = array_remove (array_cell (var), ind);
1189 if (ae)
1190 array_dispose_element (ae);
1191 }
1192 else /* array_p (var) == 0 && assoc_p (var) == 0 */
1193 {
1194 akey = this_command_name;
1195 ind = array_expand_index (var, sub, strlen (sub) + 1, 0);
1196 this_command_name = akey;
1197 if (ind == 0)
1198 {
1199 unbind_variable (var->name);
1200 return (0);
1201 }
1202 else
1203 return -2; /* any subscript other than 0 is invalid with scalar variables */
1204 }
1205
1206 return 0;
1207 }
1208
1209 /* Format and output an array assignment in compound form VAR=(VALUES),
1210 suitable for re-use as input. */
1211 void
1212 print_array_assignment (var, quoted)
1213 SHELL_VAR *var;
1214 int quoted;
1215 {
1216 char *vstr;
1217
1218 vstr = array_to_assign (array_cell (var), quoted);
1219
1220 if (vstr == 0)
1221 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
1222 else
1223 {
1224 printf ("%s=%s\n", var->name, vstr);
1225 free (vstr);
1226 }
1227 }
1228
1229 /* Format and output an associative array assignment in compound form
1230 VAR=(VALUES), suitable for re-use as input. */
1231 void
1232 print_assoc_assignment (var, quoted)
1233 SHELL_VAR *var;
1234 int quoted;
1235 {
1236 char *vstr;
1237
1238 vstr = assoc_to_assign (assoc_cell (var), quoted);
1239
1240 if (vstr == 0)
1241 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
1242 else
1243 {
1244 printf ("%s=%s\n", var->name, vstr);
1245 free (vstr);
1246 }
1247 }
1248
1249 /***********************************************************************/
1250 /* */
1251 /* Utility functions to manage arrays and their contents for expansion */
1252 /* */
1253 /***********************************************************************/
1254
1255 /* Return 1 if NAME is a properly-formed array reference v[sub]. */
1256
1257 /* Return 1 if NAME is a properly-formed array reference v[sub]. */
1258
1259 /* When NAME is a properly-formed array reference and a non-null argument SUBP
1260 is supplied, '[' and ']' that enclose the subscript are replaced by '\0',
1261 and the pointer to the subscript in NAME is assigned to *SUBP, so that NAME
1262 and SUBP can be later used as the array name and the subscript,
1263 respectively. When SUBP is the null pointer, the original string NAME will
1264 not be modified. */
1265 /* We need to reserve 1 for FLAGS, which we pass to skipsubscript. */
1266 int
1267 tokenize_array_reference (name, flags, subp)
1268 char *name;
1269 int flags;
1270 char **subp;
1271 {
1272 char *t;
1273 int r, len, isassoc, ssflags;
1274 SHELL_VAR *entry;
1275
1276 t = mbschr (name, '['); /* ] */
1277 isassoc = 0;
1278 if (t)
1279 {
1280 *t = '\0';
1281 r = legal_identifier (name);
1282 if (flags & VA_NOEXPAND) /* Don't waste a lookup if we don't need one */
1283 isassoc = (entry = find_variable (name)) && assoc_p (entry);
1284 *t = '[';
1285 if (r == 0)
1286 return 0;
1287
1288 ssflags = 0;
1289 if (isassoc && ((flags & (VA_NOEXPAND|VA_ONEWORD)) == (VA_NOEXPAND|VA_ONEWORD)))
1290 len = strlen (t) - 1;
1291 else if (isassoc)
1292 {
1293 if (flags & VA_NOEXPAND)
1294 ssflags |= 1;
1295 len = skipsubscript (t, 0, ssflags);
1296 }
1297 else
1298 /* Check for a properly-terminated non-null subscript. */
1299 len = skipsubscript (t, 0, 0); /* arithmetic expression */
1300
1301 if (t[len] != ']' || len == 1 || t[len+1] != '\0')
1302 return 0;
1303
1304 #if 0
1305 /* Could check and allow subscripts consisting only of whitespace for
1306 existing associative arrays, using isassoc */
1307 for (r = 1; r < len; r++)
1308 if (whitespace (t[r]) == 0)
1309 break;
1310 if (r == len)
1311 return 0; /* Fail if the subscript contains only whitespaces. */
1312 #endif
1313
1314 if (subp)
1315 {
1316 t[0] = t[len] = '\0';
1317 *subp = t + 1;
1318 }
1319
1320 /* This allows blank subscripts */
1321 return 1;
1322 }
1323 return 0;
1324 }
1325
1326 /* Return 1 if NAME is a properly-formed array reference v[sub]. */
1327
1328 /* We need to reserve 1 for FLAGS, which we pass to skipsubscript. */
1329 int
1330 valid_array_reference (name, flags)
1331 const char *name;
1332 int flags;
1333 {
1334 return tokenize_array_reference ((char *)name, flags, (char **)NULL);
1335 }
1336
1337 /* Expand the array index beginning at S and extending LEN characters. */
1338 arrayind_t
1339 array_expand_index (var, s, len, flags)
1340 SHELL_VAR *var;
1341 char *s;
1342 int len;
1343 int flags;
1344 {
1345 char *exp, *t, *savecmd;
1346 int expok, eflag;
1347 arrayind_t val;
1348
1349 exp = (char *)xmalloc (len);
1350 strncpy (exp, s, len - 1);
1351 exp[len - 1] = '\0';
1352 #if 0 /* TAG: maybe bash-5.2 */
1353 if ((flags & AV_NOEXPAND) == 0)
1354 t = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH|Q_ARRAYSUB); /* XXX - Q_ARRAYSUB for future use */
1355 else
1356 t = exp;
1357 #else
1358 t = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH|Q_ARRAYSUB); /* XXX - Q_ARRAYSUB for future use */
1359 #endif
1360 savecmd = this_command_name;
1361 this_command_name = (char *)NULL;
1362 eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
1363 val = evalexp (t, eflag, &expok); /* XXX - was 0 but we expanded exp already */
1364 this_command_name = savecmd;
1365 if (t != exp)
1366 free (t);
1367 free (exp);
1368 if (expok == 0)
1369 {
1370 set_exit_status (EXECUTION_FAILURE);
1371
1372 if (no_longjmp_on_fatal_error)
1373 return 0;
1374 top_level_cleanup ();
1375 jump_to_top_level (DISCARD);
1376 }
1377 return val;
1378 }
1379
1380 /* Return the name of the variable specified by S without any subscript.
1381 If SUBP is non-null, return a pointer to the start of the subscript
1382 in *SUBP. If LENP is non-null, the length of the subscript is returned
1383 in *LENP. This returns newly-allocated memory. */
1384 char *
1385 array_variable_name (s, flags, subp, lenp)
1386 const char *s;
1387 int flags;
1388 char **subp;
1389 int *lenp;
1390 {
1391 char *t, *ret;
1392 int ind, ni, ssflags;
1393
1394 t = mbschr (s, '[');
1395 if (t == 0)
1396 {
1397 if (subp)
1398 *subp = t;
1399 if (lenp)
1400 *lenp = 0;
1401 return ((char *)NULL);
1402 }
1403 ind = t - s;
1404 if ((flags & (AV_NOEXPAND|AV_ONEWORD)) == (AV_NOEXPAND|AV_ONEWORD))
1405 ni = strlen (s) - 1;
1406 else
1407 {
1408 ssflags = 0;
1409 if (flags & AV_NOEXPAND)
1410 ssflags |= 1;
1411 ni = skipsubscript (s, ind, ssflags);
1412 }
1413 if (ni <= ind + 1 || s[ni] != ']')
1414 {
1415 err_badarraysub (s);
1416 if (subp)
1417 *subp = t;
1418 if (lenp)
1419 *lenp = 0;
1420 return ((char *)NULL);
1421 }
1422
1423 *t = '\0';
1424 ret = savestring (s);
1425 *t++ = '['; /* ] */
1426
1427 if (subp)
1428 *subp = t;
1429 if (lenp)
1430 *lenp = ni - ind;
1431
1432 return ret;
1433 }
1434
1435 /* Return the variable specified by S without any subscript. If SUBP is
1436 non-null, return a pointer to the start of the subscript in *SUBP.
1437 If LENP is non-null, the length of the subscript is returned in *LENP. */
1438 SHELL_VAR *
1439 array_variable_part (s, flags, subp, lenp)
1440 const char *s;
1441 int flags;
1442 char **subp;
1443 int *lenp;
1444 {
1445 char *t;
1446 SHELL_VAR *var;
1447
1448 t = array_variable_name (s, flags, subp, lenp);
1449 if (t == 0)
1450 return ((SHELL_VAR *)NULL);
1451 var = find_variable (t); /* XXX - handle namerefs here? */
1452
1453 free (t);
1454 return var; /* now return invisible variables; caller must handle */
1455 }
1456
1457 #define INDEX_ERROR() \
1458 do \
1459 { \
1460 if (var) \
1461 err_badarraysub (var->name); \
1462 else \
1463 { \
1464 t[-1] = '\0'; \
1465 err_badarraysub (s); \
1466 t[-1] = '['; /* ] */\
1467 } \
1468 return ((char *)NULL); \
1469 } \
1470 while (0)
1471
1472 /* Return a string containing the elements in the array and subscript
1473 described by S. If the subscript is * or @, obeys quoting rules akin
1474 to the expansion of $* and $@ including double quoting. If RTYPE
1475 is non-null it gets 1 if the array reference is name[*], 2 if the
1476 reference is name[@], and 0 otherwise. */
1477 static char *
1478 array_value_internal (s, quoted, flags, estatep)
1479 const char *s;
1480 int quoted, flags;
1481 array_eltstate_t *estatep;
1482 {
1483 int len, isassoc, subtype;
1484 arrayind_t ind;
1485 char *akey;
1486 char *retval, *t, *temp;
1487 WORD_LIST *l;
1488 SHELL_VAR *var;
1489
1490 var = array_variable_part (s, flags, &t, &len); /* XXX */
1491
1492 /* Expand the index, even if the variable doesn't exist, in case side
1493 effects are needed, like ${w[i++]} where w is unset. */
1494 #if 0
1495 if (var == 0)
1496 return (char *)NULL;
1497 #endif
1498
1499 if (len == 0)
1500 return ((char *)NULL); /* error message already printed */
1501
1502 isassoc = var && assoc_p (var);
1503 /* [ */
1504 akey = 0;
1505 subtype = 0;
1506 if (estatep)
1507 estatep->value = (char *)NULL;
1508
1509 /* Backwards compatibility: we only change the behavior of A[@] and A[*]
1510 for associative arrays, and the caller has to request it. */
1511 if ((isassoc == 0 || (flags & AV_ATSTARKEYS) == 0) && ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
1512 {
1513 if (estatep)
1514 estatep->subtype = (t[0] == '*') ? 1 : 2;
1515 if ((flags & AV_ALLOWALL) == 0)
1516 {
1517 err_badarraysub (s);
1518 return ((char *)NULL);
1519 }
1520 else if (var == 0 || value_cell (var) == 0)
1521 return ((char *)NULL);
1522 else if (invisible_p (var))
1523 return ((char *)NULL);
1524 else if (array_p (var) == 0 && assoc_p (var) == 0)
1525 {
1526 if (estatep)
1527 estatep->type = ARRAY_SCALAR;
1528 l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
1529 }
1530 else if (assoc_p (var))
1531 {
1532 if (estatep)
1533 estatep->type = ARRAY_ASSOC;
1534 l = assoc_to_word_list (assoc_cell (var));
1535 if (l == (WORD_LIST *)NULL)
1536 return ((char *)NULL);
1537 }
1538 else
1539 {
1540 if (estatep)
1541 estatep->type = ARRAY_INDEXED;
1542 l = array_to_word_list (array_cell (var));
1543 if (l == (WORD_LIST *)NULL)
1544 return ((char *) NULL);
1545 }
1546
1547 /* Caller of array_value takes care of inspecting estatep->subtype and
1548 duplicating retval if subtype == 0, so this is not a memory leak */
1549 if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
1550 {
1551 temp = string_list_dollar_star (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0);
1552 retval = quote_string (temp);
1553 free (temp);
1554 }
1555 else /* ${name[@]} or unquoted ${name[*]} */
1556 retval = string_list_dollar_at (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0);
1557
1558 dispose_words (l);
1559 }
1560 else
1561 {
1562 if (estatep)
1563 estatep->subtype = 0;
1564 if (var == 0 || array_p (var) || assoc_p (var) == 0)
1565 {
1566 if ((flags & AV_USEIND) == 0 || estatep == 0)
1567 {
1568 ind = array_expand_index (var, t, len, flags);
1569 if (ind < 0)
1570 {
1571 /* negative subscripts to indexed arrays count back from end */
1572 if (var && array_p (var))
1573 ind = array_max_index (array_cell (var)) + 1 + ind;
1574 if (ind < 0)
1575 INDEX_ERROR();
1576 }
1577 if (estatep)
1578 estatep->ind = ind;
1579 }
1580 else if (estatep && (flags & AV_USEIND))
1581 ind = estatep->ind;
1582 if (estatep && var)
1583 estatep->type = array_p (var) ? ARRAY_INDEXED : ARRAY_SCALAR;
1584 }
1585 else if (assoc_p (var))
1586 {
1587 t[len - 1] = '\0';
1588 if (estatep)
1589 estatep->type = ARRAY_ASSOC;
1590 if ((flags & AV_USEIND) && estatep && estatep->key)
1591 akey = savestring (estatep->key);
1592 else if ((flags & AV_NOEXPAND) == 0)
1593 akey = expand_subscript_string (t, 0); /* [ */
1594 else
1595 akey = savestring (t);
1596 t[len - 1] = ']';
1597 if (akey == 0 || *akey == 0)
1598 {
1599 FREE (akey);
1600 INDEX_ERROR();
1601 }
1602 }
1603
1604 if (var == 0 || value_cell (var) == 0)
1605 {
1606 FREE (akey);
1607 return ((char *)NULL);
1608 }
1609 else if (invisible_p (var))
1610 {
1611 FREE (akey);
1612 return ((char *)NULL);
1613 }
1614 if (array_p (var) == 0 && assoc_p (var) == 0)
1615 retval = (ind == 0) ? value_cell (var) : (char *)NULL;
1616 else if (assoc_p (var))
1617 {
1618 retval = assoc_reference (assoc_cell (var), akey);
1619 if (estatep && estatep->key && (flags & AV_USEIND))
1620 free (akey); /* duplicated estatep->key */
1621 else if (estatep)
1622 estatep->key = akey; /* XXX - caller must manage */
1623 else /* not saving it anywhere */
1624 free (akey);
1625 }
1626 else
1627 retval = array_reference (array_cell (var), ind);
1628
1629 if (estatep)
1630 estatep->value = retval;
1631 }
1632
1633 return retval;
1634 }
1635
1636 /* Return a string containing the elements described by the array and
1637 subscript contained in S, obeying quoting for subscripts * and @. */
1638 char *
1639 array_value (s, quoted, flags, estatep)
1640 const char *s;
1641 int quoted, flags;
1642 array_eltstate_t *estatep;
1643 {
1644 char *retval;
1645
1646 retval = array_value_internal (s, quoted, flags|AV_ALLOWALL, estatep);
1647 return retval;
1648 }
1649
1650 /* Return the value of the array indexing expression S as a single string.
1651 If (FLAGS & AV_ALLOWALL) is 0, do not allow `@' and `*' subscripts. This
1652 is used by other parts of the shell such as the arithmetic expression
1653 evaluator in expr.c. */
1654 char *
1655 get_array_value (s, flags, estatep)
1656 const char *s;
1657 int flags;
1658 array_eltstate_t *estatep;
1659 {
1660 char *retval;
1661
1662 retval = array_value_internal (s, 0, flags, estatep);
1663 return retval;
1664 }
1665
1666 char *
1667 array_keys (s, quoted, pflags)
1668 char *s;
1669 int quoted, pflags;
1670 {
1671 int len;
1672 char *retval, *t, *temp;
1673 WORD_LIST *l;
1674 SHELL_VAR *var;
1675
1676 var = array_variable_part (s, 0, &t, &len);
1677
1678 /* [ */
1679 if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']')
1680 return (char *)NULL;
1681
1682 if (var_isset (var) == 0 || invisible_p (var))
1683 return (char *)NULL;
1684
1685 if (array_p (var) == 0 && assoc_p (var) == 0)
1686 l = add_string_to_list ("0", (WORD_LIST *)NULL);
1687 else if (assoc_p (var))
1688 l = assoc_keys_to_word_list (assoc_cell (var));
1689 else
1690 l = array_keys_to_word_list (array_cell (var));
1691 if (l == (WORD_LIST *)NULL)
1692 return ((char *) NULL);
1693
1694 retval = string_list_pos_params (t[0], l, quoted, pflags);
1695
1696 dispose_words (l);
1697 return retval;
1698 }
1699 #endif /* ARRAY_VARS */