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