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