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