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