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