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