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