]> git.ipfire.org Git - thirdparty/bash.git/blame - arrayfunc.c
fixes for HAVE_SELECT/HAVE_PSELECT; change some warning messages for nameref loops...
[thirdparty/bash.git] / arrayfunc.c
CommitLineData
f73dda09
JA
1/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
2
a9cf0031 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
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
5f49ef47 55static SHELL_VAR *bind_array_var_internal PARAMS((SHELL_VAR *, arrayind_t, char *, char *, int));
b2b78a63 56static SHELL_VAR *assign_array_element_internal PARAMS((SHELL_VAR *, char *, char *, char *, int, char *, int, array_eltstate_t *));
d11b8b46 57
5f49ef47
CR
58static void assign_assoc_from_kvlist PARAMS((SHELL_VAR *, WORD_LIST *, HASH_TABLE *, int));
59
60static char *quote_assign PARAMS((const char *));
61static void quote_array_assignment_chars PARAMS((WORD_LIST *));
c6c7ae81 62static char *quote_compound_array_word PARAMS((char *, int));
b2b78a63 63static char *array_value_internal PARAMS((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 *
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 ();
d3a24ed2
CR
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);
633e5c6d
CR
96 if (exported_p (var))
97 array_needs_making++;
f73dda09
JA
98
99 VSETATTR (var, att_array);
87d2ae2a
CR
100 if (oldval)
101 VUNSETATTR (var, att_invisible);
f73dda09 102
3475994a
CR
103 /* Make sure it's not marked as an associative array any more */
104 VUNSETATTR (var, att_assoc);
105
bddda3d2
CR
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
fdf670ea
CR
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)
af98a2a6 124 assoc_insert (hash, savestring ("0"), oldval);
fdf670ea
CR
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);
87d2ae2a
CR
138 if (oldval)
139 VUNSETATTR (var, att_invisible);
fdf670ea 140
3475994a
CR
141 /* Make sure it's not marked as an indexed array any more */
142 VUNSETATTR (var, att_array);
143
bddda3d2
CR
144 /* Since namerefs can't be array variables, turn off nameref attribute */
145 VUNSETATTR (var, att_nameref);
146
fdf670ea
CR
147 return var;
148}
149
861a1900
CR
150char *
151make_array_variable_value (entry, ind, key, value, flags)
d11b8b46
CR
152 SHELL_VAR *entry;
153 arrayind_t ind;
fdf670ea 154 char *key;
d11b8b46
CR
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);
fdf670ea
CR
167 if (assoc_p (entry))
168 newval = assoc_reference (assoc_cell (entry), key);
169 else
170 newval = array_reference (array_cell (entry), ind);
d11b8b46
CR
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;
fdf670ea 179 dentry->attributes = entry->attributes & ~(att_array|att_assoc|att_exported);
d11b8b46
CR
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
861a1900
CR
188 return newval;
189}
194cfc28
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. */
861a1900
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
d11b8b46 237 if (entry->assign_func)
fdf670ea
CR
238 (*entry->assign_func) (entry, newval, ind, key);
239 else if (assoc_p (entry))
240 assoc_insert (assoc_cell (entry), key, newval);
d11b8b46
CR
241 else
242 array_insert (array_cell (entry), ind, newval);
243 FREE (newval);
244
d2465f43 245 VUNSETATTR (entry, att_invisible); /* no longer invisible */
c2ccaa21
CR
246
247 /* check mark_modified_variables if we ever want to export array vars */
d11b8b46
CR
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 *
d11b8b46 259bind_array_variable (name, ind, value, flags)
f73dda09
JA
260 char *name;
261 arrayind_t ind;
262 char *value;
d11b8b46 263 int flags;
f73dda09
JA
264{
265 SHELL_VAR *entry;
f73dda09 266
348a457e 267 entry = find_shell_variable (name);
f73dda09 268
bddda3d2
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);
09f70f2f 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. */
fdf670ea 290 return (bind_array_var_internal (entry, ind, 0, value, flags));
f73dda09
JA
291}
292
6a8fd0ed
CR
293SHELL_VAR *
294bind_array_element (entry, ind, value, flags)
295 SHELL_VAR *entry;
296 arrayind_t ind;
297 char *value;
298 int flags;
299{
fdf670ea 300 return (bind_array_var_internal (entry, ind, 0, value, flags));
6a8fd0ed
CR
301}
302
fdf670ea
CR
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{
09f70f2f 311 if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry))
fdf670ea
CR
312 {
313 if (readonly_p (entry))
314 err_readonly (name);
315 return (entry);
316 }
317
194cfc28 318 return (bind_assoc_var_internal (entry, assoc_cell (entry), key, value, flags));
fdf670ea
CR
319}
320
b2b78a63
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
06db13a4
CR
341 assign VALUE to that array element by calling bind_array_variable().
342 Flags are ASS_ assignment flags */
f73dda09 343SHELL_VAR *
b2b78a63 344assign_array_element (name, value, flags, estatep)
f73dda09 345 char *name, *value;
d11b8b46 346 int flags;
b2b78a63 347 array_eltstate_t *estatep;
f73dda09 348{
276cb932 349 char *sub, *vname;
1d17c604 350 int sublen, isassoc, avflags;
2e412574 351 SHELL_VAR *entry;
f73dda09 352
1d17c604
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
3d31a311
CR
363 entry = find_variable (vname);
364 isassoc = entry && assoc_p (entry);
365
3fd77612
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] == ']')) ||
7b024db8
CR
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
b2b78a63 380 entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags, estatep);
276cb932 381
d70b5339
CR
382#if ARRAY_EXPORT
383 if (entry && exported_p (entry))
384 {
385 INVALIDATE_EXPORTSTR (entry);
386 array_needs_making = 1;
387 }
388#endif
389
276cb932
CR
390 free (vname);
391 return entry;
392}
393
394static SHELL_VAR *
b2b78a63 395assign_array_element_internal (entry, name, vname, sub, sublen, value, flags, estatep)
276cb932
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;
b2b78a63 403 array_eltstate_t *estatep;
276cb932 404{
b2b78a63 405 char *akey, *nkey;
276cb932 406 arrayind_t ind;
5f2dd5ff 407 char *newval;
fdf670ea 408
b2b78a63
CR
409 /* rely on the caller to initialize estatep */
410
fdf670ea 411 if (entry && assoc_p (entry))
f73dda09 412 {
fdf670ea 413 sub[sublen-1] = '\0';
06db13a4 414 if ((flags & ASS_NOEXPAND) == 0)
35bc7025 415 akey = expand_subscript_string (sub, 0); /* [ */
06db13a4
CR
416 else
417 akey = savestring (sub);
fdf670ea
CR
418 sub[sublen-1] = ']';
419 if (akey == 0 || *akey == 0)
420 {
fdf670ea 421 err_badarraysub (name);
631b20c6 422 FREE (akey);
fdf670ea
CR
423 return ((SHELL_VAR *)NULL);
424 }
b2b78a63
CR
425 if (estatep)
426 nkey = savestring (akey); /* assoc_insert/assoc_replace frees akey */
fdf670ea 427 entry = bind_assoc_variable (entry, vname, akey, value, flags);
b2b78a63
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 }
fdf670ea
CR
434 }
435 else
436 {
e297b059 437 ind = array_expand_index (entry, sub, sublen, 0);
a7ad477f 438 /* negative subscripts to indexed arrays count back from end */
adbaf2b3
CR
439 if (entry && ind < 0)
440 ind = (array_p (entry) ? array_max_index (array_cell (entry)) : 0) + 1 + ind;
fdf670ea
CR
441 if (ind < 0)
442 {
fdf670ea
CR
443 err_badarraysub (name);
444 return ((SHELL_VAR *)NULL);
445 }
446 entry = bind_array_variable (vname, ind, value, flags);
b2b78a63
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,
fdf670ea 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
fdf670ea
CR
462 for assignment (e.g., by the `read' builtin). If FLAGS&2 is non-zero, we
463 create an associative array. */
f73dda09 464SHELL_VAR *
fdf670ea 465find_or_make_array_variable (name, flags)
f73dda09 466 char *name;
fdf670ea 467 int flags;
f73dda09
JA
468{
469 SHELL_VAR *var;
470
471 var = find_variable (name);
d42cb8c1
CR
472 if (var == 0)
473 {
474 /* See if we have a nameref pointing to a variable that hasn't been
475 created yet. */
814e1ff5
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 }
d42cb8c1 482 if (var && nameref_p (var))
814e1ff5 483 {
80c3b1d4 484 if (valid_nameref_value (nameref_cell (var), 2) == 0)
814e1ff5
CR
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 }
d42cb8c1 491 }
f73dda09
JA
492
493 if (var == 0)
fdf670ea
CR
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 }
fdf670ea
CR
501 else if ((flags & 2) && array_p (var))
502 {
194cfc28 503 set_exit_status (EXECUTION_FAILURE);
fdf670ea
CR
504 report_error (_("%s: cannot convert indexed to associative array"), name);
505 return ((SHELL_VAR *)NULL);
506 }
b6a567e7
CR
507 else if (flags & 2)
508 var = assoc_p (var) ? var : convert_var_to_assoc (var);
fdf670ea 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 *
d11b8b46 518assign_array_from_string (name, value, flags)
f73dda09 519 char *name, *value;
d11b8b46 520 int flags;
f73dda09
JA
521{
522 SHELL_VAR *var;
fdf670ea 523 int vflags;
f73dda09 524
fdf670ea
CR
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
d11b8b46 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 *
d11b8b46 539assign_array_var_from_word_list (var, list, flags)
f73dda09
JA
540 SHELL_VAR *var;
541 WORD_LIST *list;
d11b8b46 542 int flags;
f73dda09
JA
543{
544 register arrayind_t i;
545 register WORD_LIST *l;
546 ARRAY *a;
547
d11b8b46
CR
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++)
589afb3c 552 bind_array_var_internal (var, i, 0, l->word->word, flags & ~ASS_APPEND);
60b80a1f
CR
553
554 VUNSETATTR (var, att_invisible); /* no longer invisible */
555
f73dda09
JA
556 return var;
557}
558
d3ad40de 559WORD_LIST *
fdf670ea
CR
560expand_compound_array_assignment (var, value, flags)
561 SHELL_VAR *var;
f73dda09 562 char *value;
d11b8b46 563 int flags;
f73dda09 564{
f73dda09 565 WORD_LIST *list, *nlist;
d3ad40de
CR
566 char *val;
567 int ni;
f73dda09 568
276cb932
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)
d3ad40de 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). */
70d7c643 586 /* XXX - this needs a rethink, maybe use split_at_delims */
5e13499c 587 list = parse_string_to_word_list (val, 1, "array assign");
f73dda09 588
70d7c643
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
194cfc28
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. */
276cb932
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
276cb932
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
d3ad40de
CR
623 return nlist;
624}
625
5f49ef47
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;
5f49ef47
CR
636
637 for (list = nlist; list; list = list->next)
638 {
5f49ef47
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
35bc7025 645 akey = expand_subscript_string (k, 0);
5f49ef47
CR
646 if (akey == 0 || *akey == 0)
647 {
648 err_badarraysub (k);
649 FREE (akey);
650 continue;
651 }
3fd77612 652
35bc7025 653 aval = expand_subscript_string (v, 0);
5f49ef47
CR
654 if (aval == 0)
655 {
656 aval = (char *)xmalloc (1);
657 aval[0] = '\0'; /* like do_assignment_internal */
5f49ef47
CR
658 }
659
660 bind_assoc_var_internal (var, h, akey, aval, flags);
3fd77612 661 free (aval);
5f49ef47
CR
662 }
663}
11262b0b
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{
9928dcb4 678 char *r, *s, *t;
11262b0b 679
35bc7025 680 t = w ? expand_subscript_string (w, 0) : 0;
9928dcb4
CR
681 s = (t && strchr (t, CTLESC)) ? quote_escapes (t) : t;
682 r = sh_single_quote (s ? s : "");
683 if (s != t)
684 free (s);
11262b0b
CR
685 free (t);
686 return r;
687}
5f49ef47
CR
688#endif
689
194cfc28 690/* Callers ensure that VAR is not NULL. Associative array assignments have not
c6c7ae81
CR
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
194cfc28
CR
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 */
d3ad40de
CR
698void
699assign_compound_array_list (var, nlist, flags)
700 SHELL_VAR *var;
701 WORD_LIST *nlist;
702 int flags;
703{
704 ARRAY *a;
194cfc28 705 HASH_TABLE *h, *nhash;
d3ad40de 706 WORD_LIST *list;
06c3a575 707 char *w, *val, *nval, *savecmd;
276cb932 708 int len, iflags, free_val;
d3ad40de 709 arrayind_t ind, last_ind;
fdf670ea 710 char *akey;
d3ad40de 711
fdf670ea 712 a = (var && array_p (var)) ? array_cell (var) : (ARRAY *)0;
194cfc28 713 nhash = h = (var && assoc_p (var)) ? assoc_cell (var) : (HASH_TABLE *)0;
fdf670ea
CR
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. */
fdf670ea
CR
720 if ((flags & ASS_APPEND) == 0)
721 {
824dfe68 722 if (a && array_p (var))
fdf670ea 723 array_flush (a);
824dfe68 724 else if (h && assoc_p (var))
194cfc28 725 nhash = assoc_create (h->nbuckets);
fdf670ea
CR
726 }
727
728 last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0;
f73dda09 729
5f49ef47 730#if ASSOC_KVPAIR_ASSIGNMENT
11262b0b 731 if (assoc_p (var) && kvpair_assignment_p (nlist))
5f49ef47
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
d11b8b46 745 for (list = nlist; list; list = list->next)
f73dda09 746 {
09f70f2f
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 */
5e13499c 753 if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
f73dda09 754 {
276cb932
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
d11b8b46
CR
760 /* XXX - changes for `+=' */
761 if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
f73dda09 762 {
fdf670ea
CR
763 if (assoc_p (var))
764 {
765 err_badarraysub (w);
766 continue;
767 }
d11b8b46 768 nval = make_variable_value (var, w, flags);
f73dda09 769 if (var->assign_func)
fdf670ea 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
3fd77612 784 if (ALL_ELEMENT_SUB (w[1]) && len == 2 && array_p (var))
f73dda09 785 {
194cfc28 786 set_exit_status (EXECUTION_FAILURE);
3fd77612 787 report_error (_("%s: cannot assign to non-numeric index"), w);
f73dda09
JA
788 continue;
789 }
790
fdf670ea 791 if (array_p (var))
f73dda09 792 {
e297b059 793 ind = array_expand_index (var, w + 1, len, 0);
a7ad477f
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;
fdf670ea
CR
797 if (ind < 0)
798 {
799 err_badarraysub (w);
800 continue;
801 }
802
803 last_ind = ind;
804 }
805 else if (assoc_p (var))
806 {
276cb932
CR
807 /* This is not performed above, see expand_compound_array_assignment */
808 w[len] = '\0'; /*[*/
35bc7025 809 akey = expand_subscript_string (w+1, 0);
276cb932
CR
810 w[len] = ']';
811 /* And we need to expand the value also, see below */
fdf670ea
CR
812 if (akey == 0 || *akey == 0)
813 {
814 err_badarraysub (w);
631b20c6 815 FREE (akey);
fdf670ea
CR
816 continue;
817 }
f73dda09 818 }
fdf670ea 819
d3ad40de 820 /* XXX - changes for `+=' -- just accept the syntax. ksh93 doesn't do this */
d11b8b46
CR
821 if (w[len + 1] == '+' && w[len + 2] == '=')
822 {
d3ad40de 823 iflags |= ASS_APPEND;
d11b8b46
CR
824 val = w + len + 3;
825 }
826 else
276cb932 827 val = w + len + 2;
f73dda09 828 }
fdf670ea
CR
829 else if (assoc_p (var))
830 {
194cfc28 831 set_exit_status (EXECUTION_FAILURE);
fdf670ea
CR
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
276cb932
CR
841 free_val = 0;
842 /* See above; we need to expand the value here */
843 if (assoc_p (var))
844 {
35bc7025 845 val = expand_subscript_string (val, 0);
e2f12fdf
CR
846 if (val == 0)
847 {
848 val = (char *)xmalloc (1);
849 val[0] = '\0'; /* like do_assignment_internal */
850 }
276cb932
CR
851 free_val = 1;
852 }
853
06c3a575 854 savecmd = this_command_name;
f73dda09
JA
855 if (integer_p (var))
856 this_command_name = (char *)NULL; /* no command name for errors */
194cfc28
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++;
06c3a575 862 this_command_name = savecmd;
276cb932
CR
863
864 if (free_val)
865 free (val);
f73dda09 866 }
194cfc28
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 }
d3ad40de
CR
874}
875
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
fdf670ea 889 nlist = expand_compound_array_assignment (var, value, flags);
d3ad40de 890 assign_compound_array_list (var, nlist, flags);
f73dda09 891
d3ad40de
CR
892 if (nlist)
893 dispose_words (nlist);
60b80a1f
CR
894
895 if (var)
896 VUNSETATTR (var, att_invisible); /* no longer invisible */
897
f73dda09
JA
898 return (var);
899}
900
fdf670ea
CR
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. */
4ac1ff98
CR
904static char *
905quote_assign (string)
906 const char *string;
907{
908 size_t slen;
909 int saw_eq;
3eb2d94a 910 char *temp, *t, *subs;
4ac1ff98 911 const char *s, *send;
3eb2d94a 912 int ss, se;
4ac1ff98
CR
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;
3eb2d94a
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 }
4ac1ff98
CR
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
e33aa281 947/* Take a word W of the form [IND]=VALUE and transform it to ['IND']='VALUE'
c6c7ae81
CR
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)
9928dcb4 960 return (sh_single_quote (w)); /* XXX - quote CTLESC */
c6c7ae81
CR
961 ind = skipsubscript (w, 0, 0);
962 if (w[ind] != RBRACK)
9928dcb4 963 return (sh_single_quote (w)); /* XXX - quote CTLESC */
c6c7ae81
CR
964
965 wlen = strlen (w);
966 w[ind] = '\0';
70d7c643
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);
c6c7ae81
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);
6650b4de 977 free (sub);
c6c7ae81
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++];
9928dcb4
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);
c6c7ae81
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{
9928dcb4 1004 char *nword, *key, *value, *s, *t;
c6c7ae81
CR
1005 int ind, wlen, i;
1006
1007 if (w[0] != LBRACK)
9928dcb4 1008 return (sh_single_quote (w)); /* XXX - quote_escapes */
c6c7ae81
CR
1009 ind = skipsubscript (w, 0, 0);
1010 if (w[ind] != RBRACK)
9928dcb4 1011 return (sh_single_quote (w)); /* XXX - quote_escapes */
c6c7ae81
CR
1012
1013 w[ind] = '\0';
35bc7025 1014 t = expand_subscript_string (w+1, 0);
70d7c643
CR
1015 s = (t && strchr (t, CTLESC)) ? quote_escapes (t) : t;
1016 key = sh_single_quote (s ? s : "");
1017 if (s != t)
1018 free (s);
c6c7ae81 1019 w[ind] = RBRACK;
c6c7ae81
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
35bc7025 1033 t = expand_subscript_string (w+ind, 0);
9928dcb4
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);
c6c7ae81
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
ce3e1a8c
CR
1050 the = sign (and any `+') alone. If it's not an assignment, just single-
1051 quote the word. This is used for indexed arrays. */
c6c7ae81
CR
1052void
1053quote_compound_array_list (list, type)
1054 WORD_LIST *list;
1055 int type;
1056{
9928dcb4 1057 char *s, *t;
c6c7ae81
CR
1058 WORD_LIST *l;
1059
1060 for (l = list; l; l = l->next)
1061 {
ce3e1a8c 1062 if (l->word == 0 || l->word->word == 0)
c6c7ae81
CR
1063 continue; /* should not happen, but just in case... */
1064 if ((l->word->flags & W_ASSIGNMENT) == 0)
9928dcb4 1065 {
9928dcb4
CR
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);
9928dcb4 1070 }
c6c7ae81
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
fdf670ea 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{
4ac1ff98 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... */
df0e4bfe
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;
d0ca3503 1095 if (l->word->word[0] != '[' || mbschr (l->word->word, '=') == 0) /* ] */
f73dda09 1096 continue;
df0e4bfe 1097
4ac1ff98 1098 nword = quote_assign (l->word->word);
f73dda09
JA
1099 free (l->word->word);
1100 l->word->word = nword;
df0e4bfe 1101 l->word->flags |= W_NOGLOB; /* XXX - W_NOSPLIT also? */
f73dda09
JA
1102 }
1103}
1104
6932f7f5 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. */
0e513453
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
b304aabc
CR
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
61c476d2 1115unbind_array_element (var, sub, flags)
f73dda09
JA
1116 SHELL_VAR *var;
1117 char *sub;
61c476d2 1118 int flags;
f73dda09 1119{
f73dda09 1120 arrayind_t ind;
fdf670ea 1121 char *akey;
f73dda09
JA
1122 ARRAY_ELEMENT *ae;
1123
4657c040
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 {
06c3a575
CR
1130 if (array_p (var) || assoc_p (var))
1131 {
fb4ddc2d 1132 if (flags & VA_ALLOWALL)
fb4ddc2d
CR
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 `*' */
06c3a575
CR
1138 }
1139 else
1140 return -2; /* don't allow this to unset scalar variables */
f73dda09 1141 }
fdf670ea
CR
1142
1143 if (assoc_p (var))
f73dda09 1144 {
35bc7025 1145 akey = (flags & VA_NOEXPAND) ? sub : expand_subscript_string (sub, 0);
fdf670ea
CR
1146 if (akey == 0 || *akey == 0)
1147 {
1148 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
631b20c6 1149 FREE (akey);
fdf670ea
CR
1150 return -1;
1151 }
1152 assoc_remove (assoc_cell (var), akey);
61c476d2
CR
1153 if (akey != sub)
1154 free (akey);
f73dda09 1155 }
06c3a575 1156 else if (array_p (var))
fdf670ea 1157 {
b304aabc
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 }
4657c040 1179 ind = array_expand_index (var, sub, strlen (sub) + 1, 0);
a7ad477f
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;
fdf670ea
CR
1183 if (ind < 0)
1184 {
1185 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
1186 return -1;
1187 }
1188 ae = array_remove (array_cell (var), ind);
1189 if (ae)
1190 array_dispose_element (ae);
1191 }
06c3a575
CR
1192 else /* array_p (var) == 0 && assoc_p (var) == 0 */
1193 {
1194 akey = this_command_name;
4657c040 1195 ind = array_expand_index (var, sub, strlen (sub) + 1, 0);
06c3a575
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 }
fdf670ea 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
fdf670ea
CR
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]. */
5fab8dbf 1256
4657c040
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. */
5fab8dbf 1265/* We need to reserve 1 for FLAGS, which we pass to skipsubscript. */
f73dda09 1266int
4657c040
CR
1267tokenize_array_reference (name, flags, subp)
1268 char *name;
2171061f 1269 int flags;
4657c040 1270 char **subp;
f73dda09
JA
1271{
1272 char *t;
18612983 1273 int r, len, isassoc, ssflags;
5fab8dbf 1274 SHELL_VAR *entry;
f73dda09 1275
d0ca3503 1276 t = mbschr (name, '['); /* ] */
c87bb0a8 1277 isassoc = 0;
f73dda09
JA
1278 if (t)
1279 {
1280 *t = '\0';
1281 r = legal_identifier (name);
c87bb0a8
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;
5fab8dbf 1287
18612983 1288 ssflags = 0;
5fab8dbf
CR
1289 if (isassoc && ((flags & (VA_NOEXPAND|VA_ONEWORD)) == (VA_NOEXPAND|VA_ONEWORD)))
1290 len = strlen (t) - 1;
f19b1b73 1291 else if (isassoc)
18612983
CR
1292 {
1293 if (flags & VA_NOEXPAND)
1294 ssflags |= 1;
1295 len = skipsubscript (t, 0, ssflags);
1296 }
5fab8dbf
CR
1297 else
1298 /* Check for a properly-terminated non-null subscript. */
f19b1b73
CR
1299 len = skipsubscript (t, 0, 0); /* arithmetic expression */
1300
5fab8dbf 1301 if (t[len] != ']' || len == 1 || t[len+1] != '\0')
80c3b1d4 1302 return 0;
5fab8dbf 1303
3d31a311 1304#if 0
661f4c20 1305 /* Could check and allow subscripts consisting only of whitespace for
5fab8dbf 1306 existing associative arrays, using isassoc */
f73dda09
JA
1307 for (r = 1; r < len; r++)
1308 if (whitespace (t[r]) == 0)
4657c040
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
661f4c20
CR
1320 /* This allows blank subscripts */
1321 return 1;
f73dda09
JA
1322 }
1323 return 0;
1324}
1325
4657c040
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
e297b059 1339array_expand_index (var, s, len, flags)
d9e1f41e 1340 SHELL_VAR *var;
f73dda09
JA
1341 char *s;
1342 int len;
e297b059 1343 int flags;
f73dda09 1344{
06c3a575 1345 char *exp, *t, *savecmd;
35bc7025 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';
d514a087 1352#if 0 /* TAG: maybe bash-5.2 */
ec157dfe
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;
63706353 1357#else
b4a00022 1358 t = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH|Q_ARRAYSUB); /* XXX - Q_ARRAYSUB for future use */
63706353 1359#endif
06c3a575 1360 savecmd = this_command_name;
f73dda09 1361 this_command_name = (char *)NULL;
35bc7025 1362 eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
35bc7025 1363 val = evalexp (t, eflag, &expok); /* XXX - was 0 but we expanded exp already */
06c3a575 1364 this_command_name = savecmd;
ec157dfe
CR
1365 if (t != exp)
1366 free (t);
f73dda09
JA
1367 free (exp);
1368 if (expok == 0)
1369 {
194cfc28 1370 set_exit_status (EXECUTION_FAILURE);
c184f645 1371
3b1164fc
CR
1372 if (no_longjmp_on_fatal_error)
1373 return 0;
c184f645 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 *
64a7a624 1385array_variable_name (s, flags, subp, lenp)
f8c5768e 1386 const char *s;
64a7a624 1387 int flags;
f8c5768e 1388 char **subp;
f73dda09
JA
1389 int *lenp;
1390{
1391 char *t, *ret;
1d17c604 1392 int ind, ni, ssflags;
f73dda09 1393
d0ca3503 1394 t = mbschr (s, '[');
f73dda09 1395 if (t == 0)
5e13499c
CR
1396 {
1397 if (subp)
1398 *subp = t;
1399 if (lenp)
1400 *lenp = 0;
1401 return ((char *)NULL);
1402 }
f73dda09 1403 ind = t - s;
1d17c604
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);
5e13499c
CR
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 *
64a7a624 1439array_variable_part (s, flags, subp, lenp)
f8c5768e 1440 const char *s;
64a7a624 1441 int flags;
f8c5768e 1442 char **subp;
f73dda09
JA
1443 int *lenp;
1444{
1445 char *t;
1446 SHELL_VAR *var;
1447
64a7a624 1448 t = array_variable_name (s, flags, subp, lenp);
f73dda09
JA
1449 if (t == 0)
1450 return ((SHELL_VAR *)NULL);
bddda3d2 1451 var = find_variable (t); /* XXX - handle namerefs here? */
f73dda09
JA
1452
1453 free (t);
a37d979e 1454 return var; /* now return invisible variables; caller must handle */
f73dda09
JA
1455}
1456
67362c60
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
b1a26c01
CR
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 *
b2b78a63 1478array_value_internal (s, quoted, flags, estatep)
f8c5768e 1479 const char *s;
b2b78a63
CR
1480 int quoted, flags;
1481 array_eltstate_t *estatep;
f73dda09 1482{
b2b78a63 1483 int len, isassoc, subtype;
f73dda09 1484 arrayind_t ind;
fdf670ea 1485 char *akey;
f73dda09
JA
1486 char *retval, *t, *temp;
1487 WORD_LIST *l;
1488 SHELL_VAR *var;
1489
1d17c604 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
d3a24ed2
CR
1499 if (len == 0)
1500 return ((char *)NULL); /* error message already printed */
1501
a30f513f 1502 isassoc = var && assoc_p (var);
f73dda09 1503 /* [ */
631b20c6 1504 akey = 0;
b2b78a63
CR
1505 subtype = 0;
1506 if (estatep)
1507 estatep->value = (char *)NULL;
1508
a30f513f
CR
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 {
b2b78a63
CR
1513 if (estatep)
1514 estatep->subtype = (t[0] == '*') ? 1 : 2;
5f8cde23 1515 if ((flags & AV_ALLOWALL) == 0)
f73dda09 1516 {
7117c2d2 1517 err_badarraysub (s);
f73dda09
JA
1518 return ((char *)NULL);
1519 }
b2b78a63 1520 else if (var == 0 || value_cell (var) == 0)
7117c2d2 1521 return ((char *)NULL);
a6ae8f35
CR
1522 else if (invisible_p (var))
1523 return ((char *)NULL);
fdf670ea 1524 else if (array_p (var) == 0 && assoc_p (var) == 0)
b2b78a63
CR
1525 {
1526 if (estatep)
1527 estatep->type = ARRAY_SCALAR;
1528 l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
1529 }
fdf670ea
CR
1530 else if (assoc_p (var))
1531 {
b2b78a63
CR
1532 if (estatep)
1533 estatep->type = ARRAY_ASSOC;
fdf670ea
CR
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 {
b2b78a63 1540 if (estatep)
8f68f9f0 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
b2b78a63
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 {
32dc2bf5 1551 temp = string_list_dollar_star (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0);
553a7d66 1552 retval = quote_string (temp);
f73dda09
JA
1553 free (temp);
1554 }
1555 else /* ${name[@]} or unquoted ${name[*]} */
553a7d66 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 {
b2b78a63
CR
1562 if (estatep)
1563 estatep->subtype = 0;
fdf670ea 1564 if (var == 0 || array_p (var) || assoc_p (var) == 0)
f73dda09 1565 {
b2b78a63 1566 if ((flags & AV_USEIND) == 0 || estatep == 0)
7117c2d2 1567 {
ec157dfe 1568 ind = array_expand_index (var, t, len, flags);
67362c60 1569 if (ind < 0)
5f8cde23
CR
1570 {
1571 /* negative subscripts to indexed arrays count back from end */
1572 if (var && array_p (var))
1573 ind = array_max_index (array_cell (var)) + 1 + ind;
1574 if (ind < 0)
1575 INDEX_ERROR();
1576 }
b2b78a63
CR
1577 if (estatep)
1578 estatep->ind = ind;
7117c2d2 1579 }
b2b78a63
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 }
fdf670ea
CR
1585 else if (assoc_p (var))
1586 {
1587 t[len - 1] = '\0';
b2b78a63
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)
35bc7025 1593 akey = expand_subscript_string (t, 0); /* [ */
a57ed9e9
CR
1594 else
1595 akey = savestring (t);
fdf670ea
CR
1596 t[len - 1] = ']';
1597 if (akey == 0 || *akey == 0)
631b20c6
CR
1598 {
1599 FREE (akey);
1600 INDEX_ERROR();
1601 }
fdf670ea 1602 }
b2b78a63
CR
1603
1604 if (var == 0 || value_cell (var) == 0)
631b20c6 1605 {
b2b78a63 1606 FREE (akey);
631b20c6
CR
1607 return ((char *)NULL);
1608 }
a6ae8f35
CR
1609 else if (invisible_p (var))
1610 {
b2b78a63 1611 FREE (akey);
a6ae8f35
CR
1612 return ((char *)NULL);
1613 }
fdf670ea 1614 if (array_p (var) == 0 && assoc_p (var) == 0)
b2b78a63 1615 retval = (ind == 0) ? value_cell (var) : (char *)NULL;
fdf670ea 1616 else if (assoc_p (var))
68dfe178
CR
1617 {
1618 retval = assoc_reference (assoc_cell (var), akey);
b2b78a63
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);
68dfe178 1625 }
fdf670ea
CR
1626 else
1627 retval = array_reference (array_cell (var), ind);
b2b78a63
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 *
b2b78a63 1639array_value (s, quoted, flags, estatep)
f8c5768e 1640 const char *s;
b2b78a63
CR
1641 int quoted, flags;
1642 array_eltstate_t *estatep;
f73dda09 1643{
b2b78a63
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.
5f8cde23
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 *
b2b78a63 1655get_array_value (s, flags, estatep)
f8c5768e 1656 const char *s;
b2b78a63
CR
1657 int flags;
1658 array_eltstate_t *estatep;
f73dda09 1659{
b2b78a63
CR
1660 char *retval;
1661
1662 retval = array_value_internal (s, 0, flags, estatep);
1663 return retval;
f73dda09
JA
1664}
1665
d3a24ed2 1666char *
15a23d44 1667array_keys (s, quoted, pflags)
d3a24ed2 1668 char *s;
15a23d44 1669 int quoted, pflags;
d3a24ed2
CR
1670{
1671 int len;
1672 char *retval, *t, *temp;
1673 WORD_LIST *l;
1674 SHELL_VAR *var;
1675
64a7a624 1676 var = array_variable_part (s, 0, &t, &len);
d3a24ed2
CR
1677
1678 /* [ */
1679 if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']')
1680 return (char *)NULL;
1681
68dfe178
CR
1682 if (var_isset (var) == 0 || invisible_p (var))
1683 return (char *)NULL;
1684
fdf670ea 1685 if (array_p (var) == 0 && assoc_p (var) == 0)
d3a24ed2 1686 l = add_string_to_list ("0", (WORD_LIST *)NULL);
fdf670ea
CR
1687 else if (assoc_p (var))
1688 l = assoc_keys_to_word_list (assoc_cell (var));
d3a24ed2 1689 else
fdf670ea
CR
1690 l = array_keys_to_word_list (array_cell (var));
1691 if (l == (WORD_LIST *)NULL)
1692 return ((char *) NULL);
d3a24ed2 1693
15a23d44 1694 retval = string_list_pos_params (t[0], l, quoted, pflags);
d3a24ed2
CR
1695
1696 dispose_words (l);
1697 return retval;
1698}
f73dda09 1699#endif /* ARRAY_VARS */