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