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