]> git.ipfire.org Git - thirdparty/bash.git/blame - arrayfunc.c
Bash-5.0 patch 17: better fix for reaping process substitution file descriptors
[thirdparty/bash.git] / arrayfunc.c
CommitLineData
f73dda09
JA
1/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
2
a0c0a00f 3/* Copyright (C) 2001-2016 Free Software Foundation, Inc.
f73dda09
JA
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
3185942a
JA
7 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
f73dda09 11
3185942a
JA
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
f73dda09 16
3185942a
JA
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
19*/
f73dda09
JA
20
21#include "config.h"
22
23#if defined (ARRAY_VARS)
24
25#if defined (HAVE_UNISTD_H)
26# include <unistd.h>
27#endif
28#include <stdio.h>
29
b80f6443
JA
30#include "bashintl.h"
31
f73dda09 32#include "shell.h"
d233b485 33#include "execute_cmd.h"
3185942a 34#include "pathexp.h"
7117c2d2
JA
35
36#include "shmbutil.h"
a0c0a00f
CR
37#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
38# include <mbstr.h> /* mbschr */
39#endif
7117c2d2 40
f73dda09
JA
41#include "builtins/common.h"
42
d233b485
CR
43/* This variable means to not expand associative array subscripts more than
44 once, when performing variable expansion. */
45int assoc_expand_once = 0;
46
47/* Ditto for indexed array subscripts -- currently unused */
48int array_expand_once = 0;
95732b49 49
3185942a 50static SHELL_VAR *bind_array_var_internal __P((SHELL_VAR *, arrayind_t, char *, char *, int));
ac50fbac 51static SHELL_VAR *assign_array_element_internal __P((SHELL_VAR *, char *, char *, char *, int, char *, int));
f73dda09 52
3185942a 53static char *quote_assign __P((const char *));
f73dda09 54static void quote_array_assignment_chars __P((WORD_LIST *));
a0c0a00f 55static char *array_value_internal __P((const char *, int, int, int *, arrayind_t *));
f73dda09 56
b80f6443 57/* Standard error message to use when encountering an invalid array subscript */
3185942a 58const char * const bash_badsub_errmsg = N_("bad array subscript");
b80f6443 59
f73dda09
JA
60/* **************************************************************** */
61/* */
62/* Functions to manipulate array variables and perform assignments */
63/* */
64/* **************************************************************** */
65
66/* Convert a shell variable to an array variable. The original value is
67 saved as array[0]. */
68SHELL_VAR *
69convert_var_to_array (var)
70 SHELL_VAR *var;
71{
72 char *oldval;
73 ARRAY *array;
74
75 oldval = value_cell (var);
7117c2d2 76 array = array_create ();
b80f6443
JA
77 if (oldval)
78 array_insert (array, 0, oldval);
f73dda09
JA
79
80 FREE (value_cell (var));
7117c2d2
JA
81 var_setarray (var, array);
82
83 /* these aren't valid anymore */
84 var->dynamic_value = (sh_var_value_func_t *)NULL;
85 var->assign_func = (sh_var_assign_func_t *)NULL;
f73dda09
JA
86
87 INVALIDATE_EXPORTSTR (var);
95732b49
JA
88 if (exported_p (var))
89 array_needs_making++;
f73dda09
JA
90
91 VSETATTR (var, att_array);
92 VUNSETATTR (var, att_invisible);
93
a0c0a00f
CR
94 /* Make sure it's not marked as an associative array any more */
95 VUNSETATTR (var, att_assoc);
96
97 /* Since namerefs can't be array variables, turn off nameref attribute */
98 VUNSETATTR (var, att_nameref);
99
f73dda09
JA
100 return var;
101}
102
3185942a
JA
103/* Convert a shell variable to an array variable. The original value is
104 saved as array[0]. */
105SHELL_VAR *
106convert_var_to_assoc (var)
107 SHELL_VAR *var;
108{
109 char *oldval;
110 HASH_TABLE *hash;
111
112 oldval = value_cell (var);
113 hash = assoc_create (0);
114 if (oldval)
89a92869 115 assoc_insert (hash, savestring ("0"), oldval);
3185942a
JA
116
117 FREE (value_cell (var));
118 var_setassoc (var, hash);
119
120 /* these aren't valid anymore */
121 var->dynamic_value = (sh_var_value_func_t *)NULL;
122 var->assign_func = (sh_var_assign_func_t *)NULL;
123
124 INVALIDATE_EXPORTSTR (var);
125 if (exported_p (var))
126 array_needs_making++;
127
128 VSETATTR (var, att_assoc);
129 VUNSETATTR (var, att_invisible);
130
a0c0a00f
CR
131 /* Make sure it's not marked as an indexed array any more */
132 VUNSETATTR (var, att_array);
133
134 /* Since namerefs can't be array variables, turn off nameref attribute */
135 VUNSETATTR (var, att_nameref);
136
3185942a
JA
137 return var;
138}
139
ac50fbac
CR
140char *
141make_array_variable_value (entry, ind, key, value, flags)
95732b49
JA
142 SHELL_VAR *entry;
143 arrayind_t ind;
3185942a 144 char *key;
95732b49
JA
145 char *value;
146 int flags;
147{
148 SHELL_VAR *dentry;
149 char *newval;
150
151 /* If we're appending, we need the old value of the array reference, so
152 fake out make_variable_value with a dummy SHELL_VAR */
153 if (flags & ASS_APPEND)
154 {
155 dentry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
156 dentry->name = savestring (entry->name);
3185942a
JA
157 if (assoc_p (entry))
158 newval = assoc_reference (assoc_cell (entry), key);
159 else
160 newval = array_reference (array_cell (entry), ind);
95732b49
JA
161 if (newval)
162 dentry->value = savestring (newval);
163 else
164 {
165 dentry->value = (char *)xmalloc (1);
166 dentry->value[0] = '\0';
167 }
168 dentry->exportstr = 0;
3185942a 169 dentry->attributes = entry->attributes & ~(att_array|att_assoc|att_exported);
95732b49
JA
170 /* Leave the rest of the members uninitialized; the code doesn't look
171 at them. */
172 newval = make_variable_value (dentry, value, flags);
173 dispose_variable (dentry);
174 }
175 else
176 newval = make_variable_value (entry, value, flags);
177
ac50fbac
CR
178 return newval;
179}
180
181static SHELL_VAR *
182bind_array_var_internal (entry, ind, key, value, flags)
183 SHELL_VAR *entry;
184 arrayind_t ind;
185 char *key;
186 char *value;
187 int flags;
188{
189 char *newval;
190
191 newval = make_array_variable_value (entry, ind, key, value, flags);
192
95732b49 193 if (entry->assign_func)
3185942a
JA
194 (*entry->assign_func) (entry, newval, ind, key);
195 else if (assoc_p (entry))
196 assoc_insert (assoc_cell (entry), key, newval);
95732b49
JA
197 else
198 array_insert (array_cell (entry), ind, newval);
199 FREE (newval);
200
35751626 201 VUNSETATTR (entry, att_invisible); /* no longer invisible */
d233b485
CR
202
203 /* check mark_modified_variables if we ever want to export array vars */
95732b49
JA
204 return (entry);
205}
206
f73dda09
JA
207/* Perform an array assignment name[ind]=value. If NAME already exists and
208 is not an array, and IND is 0, perform name=value instead. If NAME exists
209 and is not an array, and IND is not 0, convert it into an array with the
210 existing value as name[0].
211
212 If NAME does not exist, just create an array variable, no matter what
213 IND's value may be. */
214SHELL_VAR *
95732b49 215bind_array_variable (name, ind, value, flags)
f73dda09
JA
216 char *name;
217 arrayind_t ind;
218 char *value;
95732b49 219 int flags;
f73dda09
JA
220{
221 SHELL_VAR *entry;
f73dda09 222
ac50fbac 223 entry = find_shell_variable (name);
f73dda09 224
a0c0a00f
CR
225 if (entry == (SHELL_VAR *) 0)
226 {
227 /* Is NAME a nameref variable that points to an unset variable? */
228 entry = find_variable_nameref_for_create (name, 0);
229 if (entry == INVALID_NAMEREF_VALUE)
230 return ((SHELL_VAR *)0);
231 if (entry && nameref_p (entry))
232 entry = make_new_array_variable (nameref_cell (entry));
233 }
f73dda09
JA
234 if (entry == (SHELL_VAR *) 0)
235 entry = make_new_array_variable (name);
a0c0a00f 236 else if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry))
f73dda09
JA
237 {
238 if (readonly_p (entry))
7117c2d2 239 err_readonly (name);
f73dda09
JA
240 return (entry);
241 }
242 else if (array_p (entry) == 0)
243 entry = convert_var_to_array (entry);
244
245 /* ENTRY is an array variable, and ARRAY points to the value. */
3185942a
JA
246 return (bind_array_var_internal (entry, ind, 0, value, flags));
247}
248
249SHELL_VAR *
250bind_array_element (entry, ind, value, flags)
251 SHELL_VAR *entry;
252 arrayind_t ind;
253 char *value;
254 int flags;
255{
256 return (bind_array_var_internal (entry, ind, 0, value, flags));
257}
258
259SHELL_VAR *
260bind_assoc_variable (entry, name, key, value, flags)
261 SHELL_VAR *entry;
262 char *name;
263 char *key;
264 char *value;
265 int flags;
266{
a0c0a00f 267 if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry))
3185942a
JA
268 {
269 if (readonly_p (entry))
270 err_readonly (name);
271 return (entry);
272 }
273
274 return (bind_array_var_internal (entry, 0, key, value, flags));
f73dda09
JA
275}
276
277/* Parse NAME, a lhs of an assignment statement of the form v[s], and
d233b485
CR
278 assign VALUE to that array element by calling bind_array_variable().
279 Flags are ASS_ assignment flags */
f73dda09 280SHELL_VAR *
95732b49 281assign_array_element (name, value, flags)
f73dda09 282 char *name, *value;
95732b49 283 int flags;
f73dda09 284{
ac50fbac 285 char *sub, *vname;
d233b485
CR
286 int sublen, isassoc;
287 SHELL_VAR *entry;
f73dda09 288
d233b485 289 vname = array_variable_name (name, (flags & ASS_NOEXPAND) != 0, &sub, &sublen);
f73dda09
JA
290
291 if (vname == 0)
292 return ((SHELL_VAR *)NULL);
293
d233b485
CR
294 entry = find_variable (vname);
295 isassoc = entry && assoc_p (entry);
296
297 if (((isassoc == 0 || (flags & ASS_NOEXPAND) == 0) && (ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']')) || (sublen <= 1))
f73dda09
JA
298 {
299 free (vname);
7117c2d2 300 err_badarraysub (name);
f73dda09
JA
301 return ((SHELL_VAR *)NULL);
302 }
303
ac50fbac
CR
304 entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags);
305
306 free (vname);
307 return entry;
308}
309
310static SHELL_VAR *
311assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
312 SHELL_VAR *entry;
313 char *name; /* only used for error messages */
314 char *vname;
315 char *sub;
316 int sublen;
317 char *value;
318 int flags;
319{
320 char *akey;
321 arrayind_t ind;
3185942a
JA
322
323 if (entry && assoc_p (entry))
f73dda09 324 {
3185942a 325 sub[sublen-1] = '\0';
d233b485
CR
326 if ((flags & ASS_NOEXPAND) == 0)
327 akey = expand_assignment_string_to_string (sub, 0); /* [ */
328 else
329 akey = savestring (sub);
3185942a
JA
330 sub[sublen-1] = ']';
331 if (akey == 0 || *akey == 0)
332 {
3185942a 333 err_badarraysub (name);
ac50fbac 334 FREE (akey);
3185942a
JA
335 return ((SHELL_VAR *)NULL);
336 }
337 entry = bind_assoc_variable (entry, vname, akey, value, flags);
338 }
339 else
340 {
d233b485 341 ind = array_expand_index (entry, sub, sublen, 0);
ac50fbac
CR
342 /* negative subscripts to indexed arrays count back from end */
343 if (entry && ind < 0)
344 ind = (array_p (entry) ? array_max_index (array_cell (entry)) : 0) + 1 + ind;
3185942a
JA
345 if (ind < 0)
346 {
3185942a
JA
347 err_badarraysub (name);
348 return ((SHELL_VAR *)NULL);
349 }
350 entry = bind_array_variable (vname, ind, value, flags);
f73dda09 351 }
f73dda09 352
f73dda09
JA
353 return (entry);
354}
355
356/* Find the array variable corresponding to NAME. If there is no variable,
357 create a new array variable. If the variable exists but is not an array,
3185942a 358 convert it to an indexed array. If FLAGS&1 is non-zero, an existing
f73dda09 359 variable is checked for the readonly or noassign attribute in preparation
3185942a
JA
360 for assignment (e.g., by the `read' builtin). If FLAGS&2 is non-zero, we
361 create an associative array. */
f73dda09 362SHELL_VAR *
3185942a 363find_or_make_array_variable (name, flags)
f73dda09 364 char *name;
3185942a 365 int flags;
f73dda09
JA
366{
367 SHELL_VAR *var;
368
369 var = find_variable (name);
ac50fbac
CR
370 if (var == 0)
371 {
372 /* See if we have a nameref pointing to a variable that hasn't been
373 created yet. */
a0c0a00f
CR
374 var = find_variable_last_nameref (name, 1);
375 if (var && nameref_p (var) && invisible_p (var))
376 {
377 internal_warning (_("%s: removing nameref attribute"), name);
378 VUNSETATTR (var, att_nameref);
379 }
ac50fbac 380 if (var && nameref_p (var))
a0c0a00f
CR
381 {
382 if (valid_nameref_value (nameref_cell (var), 2) == 0)
383 {
384 sh_invalidid (nameref_cell (var));
385 return ((SHELL_VAR *)NULL);
386 }
387 var = (flags & 2) ? make_new_assoc_variable (nameref_cell (var)) : make_new_array_variable (nameref_cell (var));
388 }
ac50fbac 389 }
f73dda09
JA
390
391 if (var == 0)
3185942a
JA
392 var = (flags & 2) ? make_new_assoc_variable (name) : make_new_array_variable (name);
393 else if ((flags & 1) && (readonly_p (var) || noassign_p (var)))
f73dda09
JA
394 {
395 if (readonly_p (var))
7117c2d2 396 err_readonly (name);
f73dda09
JA
397 return ((SHELL_VAR *)NULL);
398 }
3185942a
JA
399 else if ((flags & 2) && array_p (var))
400 {
ac50fbac 401 last_command_exit_value = 1;
3185942a
JA
402 report_error (_("%s: cannot convert indexed to associative array"), name);
403 return ((SHELL_VAR *)NULL);
404 }
405 else if (array_p (var) == 0 && assoc_p (var) == 0)
f73dda09
JA
406 var = convert_var_to_array (var);
407
408 return (var);
409}
410
411/* Perform a compound assignment statement for array NAME, where VALUE is
412 the text between the parens: NAME=( VALUE ) */
413SHELL_VAR *
95732b49 414assign_array_from_string (name, value, flags)
f73dda09 415 char *name, *value;
95732b49 416 int flags;
f73dda09
JA
417{
418 SHELL_VAR *var;
3185942a 419 int vflags;
f73dda09 420
3185942a
JA
421 vflags = 1;
422 if (flags & ASS_MKASSOC)
423 vflags |= 2;
424
425 var = find_or_make_array_variable (name, vflags);
f73dda09
JA
426 if (var == 0)
427 return ((SHELL_VAR *)NULL);
428
95732b49 429 return (assign_array_var_from_string (var, value, flags));
f73dda09
JA
430}
431
432/* Sequentially assign the indices of indexed array variable VAR from the
433 words in LIST. */
434SHELL_VAR *
95732b49 435assign_array_var_from_word_list (var, list, flags)
f73dda09
JA
436 SHELL_VAR *var;
437 WORD_LIST *list;
95732b49 438 int flags;
f73dda09
JA
439{
440 register arrayind_t i;
441 register WORD_LIST *l;
442 ARRAY *a;
443
95732b49
JA
444 a = array_cell (var);
445 i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
446
447 for (l = list; l; l = l->next, i++)
a0c0a00f 448 bind_array_var_internal (var, i, 0, l->word->word, flags & ~ASS_APPEND);
d2744e05
CR
449
450 VUNSETATTR (var, att_invisible); /* no longer invisible */
451
f73dda09
JA
452 return var;
453}
454
0628567a 455WORD_LIST *
3185942a
JA
456expand_compound_array_assignment (var, value, flags)
457 SHELL_VAR *var;
f73dda09 458 char *value;
95732b49 459 int flags;
f73dda09 460{
f73dda09 461 WORD_LIST *list, *nlist;
0628567a
JA
462 char *val;
463 int ni;
f73dda09 464
ac50fbac
CR
465 /* This condition is true when invoked from the declare builtin with a
466 command like
467 declare -a d='([1]="" [2]="bdef" [5]="hello world" "test")' */
f73dda09
JA
468 if (*value == '(') /*)*/
469 {
470 ni = 1;
471 val = extract_array_assignment_list (value, &ni);
472 if (val == 0)
0628567a 473 return (WORD_LIST *)NULL;
f73dda09
JA
474 }
475 else
476 val = value;
477
478 /* Expand the value string into a list of words, performing all the
479 shell expansions including pathname generation and word splitting. */
480 /* First we split the string on whitespace, using the shell parser
481 (ksh93 seems to do this). */
b80f6443 482 list = parse_string_to_word_list (val, 1, "array assign");
f73dda09 483
ac50fbac
CR
484 if (var && assoc_p (var))
485 {
486 if (val != value)
487 free (val);
488 return list;
489 }
490
f73dda09 491 /* If we're using [subscript]=value, we need to quote each [ and ] to
ac50fbac
CR
492 prevent unwanted filename expansion. This doesn't need to be done
493 for associative array expansion, since that uses a different expansion
494 function (see assign_compound_array_list below). */
f73dda09
JA
495 if (list)
496 quote_array_assignment_chars (list);
497
498 /* Now that we've split it, perform the shell expansions on each
499 word in the list. */
500 nlist = list ? expand_words_no_vars (list) : (WORD_LIST *)NULL;
501
502 dispose_words (list);
503
504 if (val != value)
505 free (val);
506
0628567a
JA
507 return nlist;
508}
509
0001803f 510/* Callers ensure that VAR is not NULL */
0628567a
JA
511void
512assign_compound_array_list (var, nlist, flags)
513 SHELL_VAR *var;
514 WORD_LIST *nlist;
515 int flags;
516{
517 ARRAY *a;
3185942a 518 HASH_TABLE *h;
0628567a 519 WORD_LIST *list;
a0c0a00f 520 char *w, *val, *nval, *savecmd;
ac50fbac 521 int len, iflags, free_val;
0628567a 522 arrayind_t ind, last_ind;
3185942a 523 char *akey;
0628567a 524
3185942a
JA
525 a = (var && array_p (var)) ? array_cell (var) : (ARRAY *)0;
526 h = (var && assoc_p (var)) ? assoc_cell (var) : (HASH_TABLE *)0;
527
528 akey = (char *)0;
529 ind = 0;
f73dda09
JA
530
531 /* Now that we are ready to assign values to the array, kill the existing
532 value. */
3185942a
JA
533 if ((flags & ASS_APPEND) == 0)
534 {
0001803f 535 if (a && array_p (var))
3185942a 536 array_flush (a);
0001803f 537 else if (h && assoc_p (var))
3185942a
JA
538 assoc_flush (h);
539 }
540
541 last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0;
f73dda09 542
95732b49 543 for (list = nlist; list; list = list->next)
f73dda09 544 {
a0c0a00f
CR
545 /* Don't allow var+=(values) to make assignments in VALUES append to
546 existing values by default. */
547 iflags = flags & ~ASS_APPEND;
f73dda09
JA
548 w = list->word->word;
549
550 /* We have a word of the form [ind]=value */
b80f6443 551 if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
f73dda09 552 {
ac50fbac
CR
553 /* Don't have to handle embedded quotes specially any more, since
554 associative array subscripts have not been expanded yet (see
555 above). */
556 len = skipsubscript (w, 0, 0);
f73dda09 557
95732b49
JA
558 /* XXX - changes for `+=' */
559 if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
f73dda09 560 {
3185942a
JA
561 if (assoc_p (var))
562 {
563 err_badarraysub (w);
564 continue;
565 }
95732b49 566 nval = make_variable_value (var, w, flags);
f73dda09 567 if (var->assign_func)
3185942a 568 (*var->assign_func) (var, nval, last_ind, 0);
f73dda09 569 else
7117c2d2 570 array_insert (a, last_ind, nval);
f73dda09
JA
571 FREE (nval);
572 last_ind++;
573 continue;
574 }
575
576 if (len == 1)
577 {
7117c2d2 578 err_badarraysub (w);
f73dda09
JA
579 continue;
580 }
581
582 if (ALL_ELEMENT_SUB (w[1]) && len == 2)
583 {
ac50fbac 584 last_command_exit_value = 1;
3185942a
JA
585 if (assoc_p (var))
586 report_error (_("%s: invalid associative array key"), w);
587 else
588 report_error (_("%s: cannot assign to non-numeric index"), w);
f73dda09
JA
589 continue;
590 }
591
3185942a 592 if (array_p (var))
f73dda09 593 {
d233b485 594 ind = array_expand_index (var, w + 1, len, 0);
ac50fbac
CR
595 /* negative subscripts to indexed arrays count back from end */
596 if (ind < 0)
597 ind = array_max_index (array_cell (var)) + 1 + ind;
3185942a
JA
598 if (ind < 0)
599 {
600 err_badarraysub (w);
601 continue;
602 }
603
604 last_ind = ind;
f73dda09 605 }
3185942a
JA
606 else if (assoc_p (var))
607 {
ac50fbac
CR
608 /* This is not performed above, see expand_compound_array_assignment */
609 w[len] = '\0'; /*[*/
610 akey = expand_assignment_string_to_string (w+1, 0);
611 w[len] = ']';
612 /* And we need to expand the value also, see below */
3185942a
JA
613 if (akey == 0 || *akey == 0)
614 {
615 err_badarraysub (w);
ac50fbac 616 FREE (akey);
3185942a
JA
617 continue;
618 }
619 }
620
0628567a 621 /* XXX - changes for `+=' -- just accept the syntax. ksh93 doesn't do this */
95732b49
JA
622 if (w[len + 1] == '+' && w[len + 2] == '=')
623 {
0628567a 624 iflags |= ASS_APPEND;
95732b49
JA
625 val = w + len + 3;
626 }
627 else
ac50fbac 628 val = w + len + 2;
f73dda09 629 }
3185942a
JA
630 else if (assoc_p (var))
631 {
ac50fbac 632 last_command_exit_value = 1;
3185942a
JA
633 report_error (_("%s: %s: must use subscript when assigning associative array"), var->name, w);
634 continue;
635 }
f73dda09
JA
636 else /* No [ind]=value, just a stray `=' */
637 {
638 ind = last_ind;
639 val = w;
640 }
641
ac50fbac
CR
642 free_val = 0;
643 /* See above; we need to expand the value here */
644 if (assoc_p (var))
645 {
646 val = expand_assignment_string_to_string (val, 0);
01657c64
CR
647 if (val == 0)
648 {
649 val = (char *)xmalloc (1);
650 val[0] = '\0'; /* like do_assignment_internal */
651 }
ac50fbac
CR
652 free_val = 1;
653 }
654
a0c0a00f 655 savecmd = this_command_name;
f73dda09
JA
656 if (integer_p (var))
657 this_command_name = (char *)NULL; /* no command name for errors */
3185942a 658 bind_array_var_internal (var, ind, akey, val, iflags);
f73dda09 659 last_ind++;
a0c0a00f 660 this_command_name = savecmd;
ac50fbac
CR
661
662 if (free_val)
663 free (val);
f73dda09 664 }
0628567a 665}
f73dda09 666
0628567a
JA
667/* Perform a compound array assignment: VAR->name=( VALUE ). The
668 VALUE has already had the parentheses stripped. */
669SHELL_VAR *
670assign_array_var_from_string (var, value, flags)
671 SHELL_VAR *var;
672 char *value;
673 int flags;
674{
675 WORD_LIST *nlist;
676
677 if (value == 0)
678 return var;
679
3185942a 680 nlist = expand_compound_array_assignment (var, value, flags);
0628567a
JA
681 assign_compound_array_list (var, nlist, flags);
682
683 if (nlist)
684 dispose_words (nlist);
d2744e05
CR
685
686 if (var)
687 VUNSETATTR (var, att_invisible); /* no longer invisible */
688
f73dda09
JA
689 return (var);
690}
691
3185942a
JA
692/* Quote globbing chars and characters in $IFS before the `=' in an assignment
693 statement (usually a compound array assignment) to protect them from
694 unwanted filename expansion or word splitting. */
695static char *
696quote_assign (string)
697 const char *string;
698{
699 size_t slen;
700 int saw_eq;
0001803f 701 char *temp, *t, *subs;
3185942a 702 const char *s, *send;
0001803f 703 int ss, se;
3185942a
JA
704 DECLARE_MBSTATE;
705
706 slen = strlen (string);
707 send = string + slen;
708
709 t = temp = (char *)xmalloc (slen * 2 + 1);
710 saw_eq = 0;
711 for (s = string; *s; )
712 {
713 if (*s == '=')
714 saw_eq = 1;
0001803f
CR
715 if (saw_eq == 0 && *s == '[') /* looks like a subscript */
716 {
717 ss = s - string;
718 se = skipsubscript (string, ss, 0);
719 subs = substring (s, ss, se);
720 *t++ = '\\';
721 strcpy (t, subs);
722 t += se - ss;
723 *t++ = '\\';
724 *t++ = ']';
725 s += se + 1;
726 free (subs);
727 continue;
728 }
3185942a
JA
729 if (saw_eq == 0 && (glob_char_p (s) || isifs (*s)))
730 *t++ = '\\';
731
732 COPY_CHAR_P (t, s, send);
733 }
734 *t = '\0';
735 return temp;
736}
737
f73dda09 738/* For each word in a compound array assignment, if the word looks like
3185942a 739 [ind]=value, quote globbing chars and characters in $IFS before the `='. */
f73dda09
JA
740static void
741quote_array_assignment_chars (list)
742 WORD_LIST *list;
743{
3185942a 744 char *nword;
f73dda09
JA
745 WORD_LIST *l;
746
747 for (l = list; l; l = l->next)
748 {
749 if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
750 continue; /* should not happen, but just in case... */
ac50fbac
CR
751 /* Don't bother if it hasn't been recognized as an assignment or
752 doesn't look like [ind]=value */
753 if ((l->word->flags & W_ASSIGNMENT) == 0)
754 continue;
0001803f 755 if (l->word->word[0] != '[' || mbschr (l->word->word, '=') == 0) /* ] */
f73dda09 756 continue;
ac50fbac 757
3185942a 758 nword = quote_assign (l->word->word);
f73dda09
JA
759 free (l->word->word);
760 l->word->word = nword;
ac50fbac 761 l->word->flags |= W_NOGLOB; /* XXX - W_NOSPLIT also? */
f73dda09
JA
762 }
763}
764
89a92869 765/* skipsubscript moved to subst.c to use private functions. 2009/02/24. */
f73dda09
JA
766
767/* This function is called with SUB pointing to just after the beginning
768 `[' of an array subscript and removes the array element to which SUB
769 expands from array VAR. A subscript of `*' or `@' unsets the array. */
d233b485 770/* If FLAGS&1 we don't expand the subscript; we just use it as-is. */
f73dda09 771int
d233b485 772unbind_array_element (var, sub, flags)
f73dda09
JA
773 SHELL_VAR *var;
774 char *sub;
d233b485 775 int flags;
f73dda09
JA
776{
777 int len;
778 arrayind_t ind;
3185942a 779 char *akey;
f73dda09
JA
780 ARRAY_ELEMENT *ae;
781
d233b485 782 len = skipsubscript (sub, 0, (flags&1) || (var && assoc_p(var))); /* XXX */
f73dda09
JA
783 if (sub[len] != ']' || len == 0)
784 {
b80f6443 785 builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg));
f73dda09
JA
786 return -1;
787 }
788 sub[len] = '\0';
789
790 if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0)
791 {
a0c0a00f
CR
792 if (array_p (var) || assoc_p (var))
793 {
794 unbind_variable (var->name); /* XXX -- {array,assoc}_flush ? */
795 return (0);
796 }
797 else
798 return -2; /* don't allow this to unset scalar variables */
f73dda09 799 }
3185942a
JA
800
801 if (assoc_p (var))
f73dda09 802 {
d233b485 803 akey = (flags & 1) ? sub : expand_assignment_string_to_string (sub, 0);
3185942a
JA
804 if (akey == 0 || *akey == 0)
805 {
806 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
ac50fbac 807 FREE (akey);
3185942a
JA
808 return -1;
809 }
810 assoc_remove (assoc_cell (var), akey);
d233b485
CR
811 if (akey != sub)
812 free (akey);
3185942a 813 }
a0c0a00f 814 else if (array_p (var))
3185942a 815 {
d233b485 816 ind = array_expand_index (var, sub, len+1, 0);
ac50fbac
CR
817 /* negative subscripts to indexed arrays count back from end */
818 if (ind < 0)
819 ind = array_max_index (array_cell (var)) + 1 + ind;
3185942a
JA
820 if (ind < 0)
821 {
822 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
823 return -1;
824 }
825 ae = array_remove (array_cell (var), ind);
826 if (ae)
827 array_dispose_element (ae);
f73dda09 828 }
a0c0a00f
CR
829 else /* array_p (var) == 0 && assoc_p (var) == 0 */
830 {
831 akey = this_command_name;
d233b485 832 ind = array_expand_index (var, sub, len+1, 0);
a0c0a00f
CR
833 this_command_name = akey;
834 if (ind == 0)
835 {
836 unbind_variable (var->name);
837 return (0);
838 }
839 else
840 return -2; /* any subscript other than 0 is invalid with scalar variables */
841 }
3185942a 842
f73dda09
JA
843 return 0;
844}
845
846/* Format and output an array assignment in compound form VAR=(VALUES),
847 suitable for re-use as input. */
848void
849print_array_assignment (var, quoted)
850 SHELL_VAR *var;
851 int quoted;
852{
853 char *vstr;
854
7117c2d2 855 vstr = array_to_assign (array_cell (var), quoted);
f73dda09
JA
856
857 if (vstr == 0)
858 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
859 else
860 {
861 printf ("%s=%s\n", var->name, vstr);
862 free (vstr);
863 }
864}
865
3185942a
JA
866/* Format and output an associative array assignment in compound form
867 VAR=(VALUES), suitable for re-use as input. */
868void
869print_assoc_assignment (var, quoted)
870 SHELL_VAR *var;
871 int quoted;
872{
873 char *vstr;
874
875 vstr = assoc_to_assign (assoc_cell (var), quoted);
876
877 if (vstr == 0)
878 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
879 else
880 {
881 printf ("%s=%s\n", var->name, vstr);
882 free (vstr);
883 }
884}
885
f73dda09
JA
886/***********************************************************************/
887/* */
888/* Utility functions to manage arrays and their contents for expansion */
889/* */
890/***********************************************************************/
891
892/* Return 1 if NAME is a properly-formed array reference v[sub]. */
d233b485
CR
893
894/* We need to reserve 1 for FLAGS, which we pass to skipsubscript. */
f73dda09 895int
a0c0a00f
CR
896valid_array_reference (name, flags)
897 const char *name;
898 int flags;
f73dda09
JA
899{
900 char *t;
d233b485
CR
901 int r, len, isassoc;
902 SHELL_VAR *entry;
f73dda09 903
0001803f 904 t = mbschr (name, '['); /* ] */
d233b485 905 isassoc = 0;
f73dda09
JA
906 if (t)
907 {
908 *t = '\0';
909 r = legal_identifier (name);
d233b485
CR
910 if (flags & VA_NOEXPAND) /* Don't waste a lookup if we don't need one */
911 isassoc = (entry = find_variable (name)) && assoc_p (entry);
f73dda09
JA
912 *t = '[';
913 if (r == 0)
914 return 0;
d233b485
CR
915
916 if (isassoc && ((flags & (VA_NOEXPAND|VA_ONEWORD)) == (VA_NOEXPAND|VA_ONEWORD)))
917 len = strlen (t) - 1;
918 else if (isassoc)
919 len = skipsubscript (t, 0, flags&VA_NOEXPAND); /* VA_NOEXPAND must be 1 */
920 else
921 /* Check for a properly-terminated non-null subscript. */
922 len = skipsubscript (t, 0, 0); /* arithmetic expression */
923
924 if (t[len] != ']' || len == 1 || t[len+1] != '\0')
a0c0a00f 925 return 0;
d233b485
CR
926
927#if 0
928 /* Could check and allow subscripts consisting only of whitespace for
929 existing associative arrays, using isassoc */
f73dda09
JA
930 for (r = 1; r < len; r++)
931 if (whitespace (t[r]) == 0)
932 return 1;
933 return 0;
d233b485
CR
934#else
935 /* This allows blank subscripts */
936 return 1;
937#endif
f73dda09
JA
938 }
939 return 0;
940}
941
942/* Expand the array index beginning at S and extending LEN characters. */
943arrayind_t
d233b485 944array_expand_index (var, s, len, flags)
ac50fbac 945 SHELL_VAR *var;
f73dda09
JA
946 char *s;
947 int len;
d233b485 948 int flags;
f73dda09 949{
a0c0a00f 950 char *exp, *t, *savecmd;
f73dda09
JA
951 int expok;
952 arrayind_t val;
953
954 exp = (char *)xmalloc (len);
955 strncpy (exp, s, len - 1);
956 exp[len - 1] = '\0';
d233b485
CR
957#if 0 /* XXX - not yet -- maybe bash-5.1 */
958 if ((flags & AV_NOEXPAND) == 0)
959 t = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH|Q_ARRAYSUB); /* XXX - Q_ARRAYSUB for future use */
960 else
961 t = exp;
962#endif
a0c0a00f
CR
963 t = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH|Q_ARRAYSUB); /* XXX - Q_ARRAYSUB for future use */
964 savecmd = this_command_name;
f73dda09 965 this_command_name = (char *)NULL;
d233b485 966 val = evalexp (t, 0, &expok);
a0c0a00f 967 this_command_name = savecmd;
d233b485
CR
968 if (t != exp)
969 free (t);
f73dda09
JA
970 free (exp);
971 if (expok == 0)
972 {
973 last_command_exit_value = EXECUTION_FAILURE;
f1be666c 974
a0c0a00f
CR
975 if (no_longjmp_on_fatal_error)
976 return 0;
f1be666c 977 top_level_cleanup ();
f73dda09
JA
978 jump_to_top_level (DISCARD);
979 }
980 return val;
981}
982
983/* Return the name of the variable specified by S without any subscript.
984 If SUBP is non-null, return a pointer to the start of the subscript
985 in *SUBP. If LENP is non-null, the length of the subscript is returned
986 in *LENP. This returns newly-allocated memory. */
987char *
d233b485 988array_variable_name (s, flags, subp, lenp)
a0c0a00f 989 const char *s;
d233b485 990 int flags;
a0c0a00f 991 char **subp;
f73dda09
JA
992 int *lenp;
993{
994 char *t, *ret;
995 int ind, ni;
996
0001803f 997 t = mbschr (s, '[');
f73dda09 998 if (t == 0)
b80f6443
JA
999 {
1000 if (subp)
1001 *subp = t;
1002 if (lenp)
1003 *lenp = 0;
1004 return ((char *)NULL);
1005 }
f73dda09 1006 ind = t - s;
d233b485 1007 ni = skipsubscript (s, ind, flags); /* XXX - was 0 not flags */
f73dda09
JA
1008 if (ni <= ind + 1 || s[ni] != ']')
1009 {
7117c2d2 1010 err_badarraysub (s);
b80f6443
JA
1011 if (subp)
1012 *subp = t;
1013 if (lenp)
1014 *lenp = 0;
f73dda09
JA
1015 return ((char *)NULL);
1016 }
1017
1018 *t = '\0';
1019 ret = savestring (s);
1020 *t++ = '['; /* ] */
1021
1022 if (subp)
1023 *subp = t;
1024 if (lenp)
1025 *lenp = ni - ind;
1026
1027 return ret;
1028}
1029
1030/* Return the variable specified by S without any subscript. If SUBP is
1031 non-null, return a pointer to the start of the subscript in *SUBP.
1032 If LENP is non-null, the length of the subscript is returned in *LENP. */
1033SHELL_VAR *
d233b485 1034array_variable_part (s, flags, subp, lenp)
a0c0a00f 1035 const char *s;
d233b485 1036 int flags;
a0c0a00f 1037 char **subp;
f73dda09
JA
1038 int *lenp;
1039{
1040 char *t;
1041 SHELL_VAR *var;
1042
d233b485 1043 t = array_variable_name (s, flags, subp, lenp);
f73dda09
JA
1044 if (t == 0)
1045 return ((SHELL_VAR *)NULL);
a0c0a00f 1046 var = find_variable (t); /* XXX - handle namerefs here? */
f73dda09
JA
1047
1048 free (t);
ac50fbac 1049 return var; /* now return invisible variables; caller must handle */
f73dda09
JA
1050}
1051
495aee44
CR
1052#define INDEX_ERROR() \
1053 do \
1054 { \
1055 if (var) \
1056 err_badarraysub (var->name); \
1057 else \
1058 { \
1059 t[-1] = '\0'; \
1060 err_badarraysub (s); \
1061 t[-1] = '['; /* ] */\
1062 } \
1063 return ((char *)NULL); \
1064 } \
1065 while (0)
1066
f73dda09
JA
1067/* Return a string containing the elements in the array and subscript
1068 described by S. If the subscript is * or @, obeys quoting rules akin
7117c2d2 1069 to the expansion of $* and $@ including double quoting. If RTYPE
3185942a
JA
1070 is non-null it gets 1 if the array reference is name[*], 2 if the
1071 reference is name[@], and 0 otherwise. */
f73dda09 1072static char *
495aee44 1073array_value_internal (s, quoted, flags, rtype, indp)
a0c0a00f 1074 const char *s;
495aee44
CR
1075 int quoted, flags, *rtype;
1076 arrayind_t *indp;
f73dda09
JA
1077{
1078 int len;
1079 arrayind_t ind;
3185942a 1080 char *akey;
f73dda09
JA
1081 char *retval, *t, *temp;
1082 WORD_LIST *l;
1083 SHELL_VAR *var;
1084
d233b485 1085 var = array_variable_part (s, (flags&AV_NOEXPAND) ? 1 : 0, &t, &len); /* XXX */
f73dda09 1086
7117c2d2
JA
1087 /* Expand the index, even if the variable doesn't exist, in case side
1088 effects are needed, like ${w[i++]} where w is unset. */
1089#if 0
f73dda09
JA
1090 if (var == 0)
1091 return (char *)NULL;
7117c2d2 1092#endif
f73dda09 1093
b80f6443
JA
1094 if (len == 0)
1095 return ((char *)NULL); /* error message already printed */
1096
f73dda09 1097 /* [ */
ac50fbac 1098 akey = 0;
f73dda09
JA
1099 if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
1100 {
7117c2d2 1101 if (rtype)
f1be666c 1102 *rtype = (t[0] == '*') ? 1 : 2;
495aee44 1103 if ((flags & AV_ALLOWALL) == 0)
f73dda09 1104 {
7117c2d2 1105 err_badarraysub (s);
f73dda09
JA
1106 return ((char *)NULL);
1107 }
495aee44 1108 else if (var == 0 || value_cell (var) == 0) /* XXX - check for invisible_p(var) ? */
7117c2d2 1109 return ((char *)NULL);
d233b485
CR
1110 else if (invisible_p (var))
1111 return ((char *)NULL);
3185942a 1112 else if (array_p (var) == 0 && assoc_p (var) == 0)
7117c2d2 1113 l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
3185942a
JA
1114 else if (assoc_p (var))
1115 {
1116 l = assoc_to_word_list (assoc_cell (var));
1117 if (l == (WORD_LIST *)NULL)
1118 return ((char *)NULL);
1119 }
f73dda09
JA
1120 else
1121 {
1122 l = array_to_word_list (array_cell (var));
1123 if (l == (WORD_LIST *)NULL)
1124 return ((char *) NULL);
1125 }
1126
d233b485
CR
1127 /* Caller of array_value takes care of inspecting rtype and duplicating
1128 retval if rtype == 0, so this is not a memory leak */
f73dda09
JA
1129 if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
1130 {
d233b485
CR
1131 temp = string_list_dollar_star (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0);
1132 retval = quote_string (temp);
f73dda09
JA
1133 free (temp);
1134 }
1135 else /* ${name[@]} or unquoted ${name[*]} */
d233b485 1136 retval = string_list_dollar_at (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0);
f73dda09
JA
1137
1138 dispose_words (l);
1139 }
1140 else
1141 {
7117c2d2
JA
1142 if (rtype)
1143 *rtype = 0;
3185942a 1144 if (var == 0 || array_p (var) || assoc_p (var) == 0)
f73dda09 1145 {
495aee44 1146 if ((flags & AV_USEIND) == 0 || indp == 0)
7117c2d2 1147 {
d233b485 1148 ind = array_expand_index (var, t, len, flags);
495aee44 1149 if (ind < 0)
3185942a 1150 {
495aee44
CR
1151 /* negative subscripts to indexed arrays count back from end */
1152 if (var && array_p (var))
1153 ind = array_max_index (array_cell (var)) + 1 + ind;
1154 if (ind < 0)
1155 INDEX_ERROR();
3185942a 1156 }
495aee44
CR
1157 if (indp)
1158 *indp = ind;
7117c2d2 1159 }
495aee44
CR
1160 else if (indp)
1161 ind = *indp;
f73dda09 1162 }
3185942a
JA
1163 else if (assoc_p (var))
1164 {
1165 t[len - 1] = '\0';
d233b485
CR
1166 if ((flags & AV_NOEXPAND) == 0)
1167 akey = expand_assignment_string_to_string (t, 0); /* [ */
1168 else
1169 akey = savestring (t);
3185942a
JA
1170 t[len - 1] = ']';
1171 if (akey == 0 || *akey == 0)
ac50fbac
CR
1172 {
1173 FREE (akey);
1174 INDEX_ERROR();
1175 }
3185942a
JA
1176 }
1177
495aee44 1178 if (var == 0 || value_cell (var) == 0) /* XXX - check invisible_p(var) ? */
ac50fbac
CR
1179 {
1180 FREE (akey);
1181 return ((char *)NULL);
1182 }
d233b485
CR
1183 else if (invisible_p (var))
1184 {
1185 FREE (akey);
1186 return ((char *)NULL);
1187 }
3185942a 1188 if (array_p (var) == 0 && assoc_p (var) == 0)
7117c2d2 1189 return (ind == 0 ? value_cell (var) : (char *)NULL);
3185942a 1190 else if (assoc_p (var))
495aee44
CR
1191 {
1192 retval = assoc_reference (assoc_cell (var), akey);
1193 free (akey);
1194 }
3185942a
JA
1195 else
1196 retval = array_reference (array_cell (var), ind);
f73dda09
JA
1197 }
1198
1199 return retval;
1200}
1201
1202/* Return a string containing the elements described by the array and
1203 subscript contained in S, obeying quoting for subscripts * and @. */
1204char *
495aee44 1205array_value (s, quoted, flags, rtype, indp)
a0c0a00f 1206 const char *s;
495aee44
CR
1207 int quoted, flags, *rtype;
1208 arrayind_t *indp;
f73dda09 1209{
495aee44 1210 return (array_value_internal (s, quoted, flags|AV_ALLOWALL, rtype, indp));
f73dda09
JA
1211}
1212
1213/* Return the value of the array indexing expression S as a single string.
495aee44
CR
1214 If (FLAGS & AV_ALLOWALL) is 0, do not allow `@' and `*' subscripts. This
1215 is used by other parts of the shell such as the arithmetic expression
1216 evaluator in expr.c. */
f73dda09 1217char *
495aee44 1218get_array_value (s, flags, rtype, indp)
a0c0a00f 1219 const char *s;
495aee44
CR
1220 int flags, *rtype;
1221 arrayind_t *indp;
f73dda09 1222{
495aee44 1223 return (array_value_internal (s, 0, flags, rtype, indp));
f73dda09
JA
1224}
1225
b80f6443
JA
1226char *
1227array_keys (s, quoted)
1228 char *s;
1229 int quoted;
1230{
1231 int len;
1232 char *retval, *t, *temp;
1233 WORD_LIST *l;
1234 SHELL_VAR *var;
1235
d233b485 1236 var = array_variable_part (s, 0, &t, &len);
b80f6443
JA
1237
1238 /* [ */
1239 if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']')
1240 return (char *)NULL;
1241
495aee44
CR
1242 if (var_isset (var) == 0 || invisible_p (var))
1243 return (char *)NULL;
1244
3185942a 1245 if (array_p (var) == 0 && assoc_p (var) == 0)
b80f6443 1246 l = add_string_to_list ("0", (WORD_LIST *)NULL);
3185942a
JA
1247 else if (assoc_p (var))
1248 l = assoc_keys_to_word_list (assoc_cell (var));
b80f6443 1249 else
3185942a
JA
1250 l = array_keys_to_word_list (array_cell (var));
1251 if (l == (WORD_LIST *)NULL)
1252 return ((char *) NULL);
b80f6443
JA
1253
1254 if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
1255 {
d233b485 1256 temp = string_list_dollar_star (l, quoted, 0);
b80f6443
JA
1257 retval = quote_string (temp);
1258 free (temp);
1259 }
1260 else /* ${!name[@]} or unquoted ${!name[*]} */
a0c0a00f 1261 retval = string_list_dollar_at (l, quoted, 0);
b80f6443
JA
1262
1263 dispose_words (l);
1264 return retval;
1265}
f73dda09 1266#endif /* ARRAY_VARS */