]> git.ipfire.org Git - thirdparty/bash.git/blame - arrayfunc.c
Bash-4.0 patchlevel 38
[thirdparty/bash.git] / arrayfunc.c
CommitLineData
f73dda09
JA
1/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
2
3185942a 3/* Copyright (C) 2001-2009 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 *));
7117c2d2 47static char *array_value_internal __P((char *, int, int, int *));
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
410void
411assign_compound_array_list (var, nlist, flags)
412 SHELL_VAR *var;
413 WORD_LIST *nlist;
414 int flags;
415{
416 ARRAY *a;
3185942a 417 HASH_TABLE *h;
0628567a
JA
418 WORD_LIST *list;
419 char *w, *val, *nval;
420 int len, iflags;
421 arrayind_t ind, last_ind;
3185942a 422 char *akey;
0628567a 423
3185942a
JA
424 a = (var && array_p (var)) ? array_cell (var) : (ARRAY *)0;
425 h = (var && assoc_p (var)) ? assoc_cell (var) : (HASH_TABLE *)0;
426
427 akey = (char *)0;
428 ind = 0;
f73dda09
JA
429
430 /* Now that we are ready to assign values to the array, kill the existing
431 value. */
3185942a
JA
432 if ((flags & ASS_APPEND) == 0)
433 {
434 if (array_p (var) && a)
435 array_flush (a);
436 else if (assoc_p (var) && h)
437 assoc_flush (h);
438 }
439
440 last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0;
f73dda09 441
95732b49 442 for (list = nlist; list; list = list->next)
f73dda09 443 {
0628567a 444 iflags = flags;
f73dda09
JA
445 w = list->word->word;
446
447 /* We have a word of the form [ind]=value */
b80f6443 448 if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
f73dda09
JA
449 {
450 len = skipsubscript (w, 0);
451
95732b49
JA
452 /* XXX - changes for `+=' */
453 if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
f73dda09 454 {
3185942a
JA
455 if (assoc_p (var))
456 {
457 err_badarraysub (w);
458 continue;
459 }
95732b49 460 nval = make_variable_value (var, w, flags);
f73dda09 461 if (var->assign_func)
3185942a 462 (*var->assign_func) (var, nval, last_ind, 0);
f73dda09 463 else
7117c2d2 464 array_insert (a, last_ind, nval);
f73dda09
JA
465 FREE (nval);
466 last_ind++;
467 continue;
468 }
469
470 if (len == 1)
471 {
7117c2d2 472 err_badarraysub (w);
f73dda09
JA
473 continue;
474 }
475
476 if (ALL_ELEMENT_SUB (w[1]) && len == 2)
477 {
3185942a
JA
478 if (assoc_p (var))
479 report_error (_("%s: invalid associative array key"), w);
480 else
481 report_error (_("%s: cannot assign to non-numeric index"), w);
f73dda09
JA
482 continue;
483 }
484
3185942a 485 if (array_p (var))
f73dda09 486 {
3185942a
JA
487 ind = array_expand_index (w + 1, len);
488 if (ind < 0)
489 {
490 err_badarraysub (w);
491 continue;
492 }
493
494 last_ind = ind;
f73dda09 495 }
3185942a
JA
496 else if (assoc_p (var))
497 {
498 akey = substring (w, 1, len);
499 if (akey == 0 || *akey == 0)
500 {
501 err_badarraysub (w);
502 continue;
503 }
504 }
505
0628567a 506 /* XXX - changes for `+=' -- just accept the syntax. ksh93 doesn't do this */
95732b49
JA
507 if (w[len + 1] == '+' && w[len + 2] == '=')
508 {
0628567a 509 iflags |= ASS_APPEND;
95732b49
JA
510 val = w + len + 3;
511 }
512 else
513 val = w + len + 2;
f73dda09 514 }
3185942a
JA
515 else if (assoc_p (var))
516 {
517 report_error (_("%s: %s: must use subscript when assigning associative array"), var->name, w);
518 continue;
519 }
f73dda09
JA
520 else /* No [ind]=value, just a stray `=' */
521 {
522 ind = last_ind;
523 val = w;
524 }
525
526 if (integer_p (var))
527 this_command_name = (char *)NULL; /* no command name for errors */
3185942a 528 bind_array_var_internal (var, ind, akey, val, iflags);
f73dda09
JA
529 last_ind++;
530 }
0628567a 531}
f73dda09 532
0628567a
JA
533/* Perform a compound array assignment: VAR->name=( VALUE ). The
534 VALUE has already had the parentheses stripped. */
535SHELL_VAR *
536assign_array_var_from_string (var, value, flags)
537 SHELL_VAR *var;
538 char *value;
539 int flags;
540{
541 WORD_LIST *nlist;
542
543 if (value == 0)
544 return var;
545
3185942a 546 nlist = expand_compound_array_assignment (var, value, flags);
0628567a
JA
547 assign_compound_array_list (var, nlist, flags);
548
549 if (nlist)
550 dispose_words (nlist);
f73dda09
JA
551 return (var);
552}
553
3185942a
JA
554/* Quote globbing chars and characters in $IFS before the `=' in an assignment
555 statement (usually a compound array assignment) to protect them from
556 unwanted filename expansion or word splitting. */
557static char *
558quote_assign (string)
559 const char *string;
560{
561 size_t slen;
562 int saw_eq;
563 char *temp, *t;
564 const char *s, *send;
565 DECLARE_MBSTATE;
566
567 slen = strlen (string);
568 send = string + slen;
569
570 t = temp = (char *)xmalloc (slen * 2 + 1);
571 saw_eq = 0;
572 for (s = string; *s; )
573 {
574 if (*s == '=')
575 saw_eq = 1;
576 if (saw_eq == 0 && (glob_char_p (s) || isifs (*s)))
577 *t++ = '\\';
578
579 COPY_CHAR_P (t, s, send);
580 }
581 *t = '\0';
582 return temp;
583}
584
f73dda09 585/* For each word in a compound array assignment, if the word looks like
3185942a 586 [ind]=value, quote globbing chars and characters in $IFS before the `='. */
f73dda09
JA
587static void
588quote_array_assignment_chars (list)
589 WORD_LIST *list;
590{
3185942a 591 char *nword;
f73dda09
JA
592 WORD_LIST *l;
593
594 for (l = list; l; l = l->next)
595 {
596 if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
597 continue; /* should not happen, but just in case... */
598 /* Don't bother if it doesn't look like [ind]=value */
7117c2d2 599 if (l->word->word[0] != '[' || xstrchr (l->word->word, '=') == 0) /* ] */
f73dda09 600 continue;
3185942a 601 nword = quote_assign (l->word->word);
f73dda09
JA
602 free (l->word->word);
603 l->word->word = nword;
604 }
605}
606
89a92869 607/* skipsubscript moved to subst.c to use private functions. 2009/02/24. */
f73dda09
JA
608
609/* This function is called with SUB pointing to just after the beginning
610 `[' of an array subscript and removes the array element to which SUB
611 expands from array VAR. A subscript of `*' or `@' unsets the array. */
612int
613unbind_array_element (var, sub)
614 SHELL_VAR *var;
615 char *sub;
616{
617 int len;
618 arrayind_t ind;
3185942a 619 char *akey;
f73dda09
JA
620 ARRAY_ELEMENT *ae;
621
622 len = skipsubscript (sub, 0);
623 if (sub[len] != ']' || len == 0)
624 {
b80f6443 625 builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg));
f73dda09
JA
626 return -1;
627 }
628 sub[len] = '\0';
629
630 if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0)
631 {
7117c2d2 632 unbind_variable (var->name);
f73dda09
JA
633 return (0);
634 }
3185942a
JA
635
636 if (assoc_p (var))
f73dda09 637 {
3185942a
JA
638 akey = expand_assignment_string_to_string (sub, 0); /* [ */
639 if (akey == 0 || *akey == 0)
640 {
641 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
642 return -1;
643 }
644 assoc_remove (assoc_cell (var), akey);
645 }
646 else
647 {
648 ind = array_expand_index (sub, len+1);
649 if (ind < 0)
650 {
651 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
652 return -1;
653 }
654 ae = array_remove (array_cell (var), ind);
655 if (ae)
656 array_dispose_element (ae);
f73dda09 657 }
3185942a 658
f73dda09
JA
659 return 0;
660}
661
662/* Format and output an array assignment in compound form VAR=(VALUES),
663 suitable for re-use as input. */
664void
665print_array_assignment (var, quoted)
666 SHELL_VAR *var;
667 int quoted;
668{
669 char *vstr;
670
7117c2d2 671 vstr = array_to_assign (array_cell (var), quoted);
f73dda09
JA
672
673 if (vstr == 0)
674 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
675 else
676 {
677 printf ("%s=%s\n", var->name, vstr);
678 free (vstr);
679 }
680}
681
3185942a
JA
682/* Format and output an associative array assignment in compound form
683 VAR=(VALUES), suitable for re-use as input. */
684void
685print_assoc_assignment (var, quoted)
686 SHELL_VAR *var;
687 int quoted;
688{
689 char *vstr;
690
691 vstr = assoc_to_assign (assoc_cell (var), quoted);
692
693 if (vstr == 0)
694 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
695 else
696 {
697 printf ("%s=%s\n", var->name, vstr);
698 free (vstr);
699 }
700}
701
f73dda09
JA
702/***********************************************************************/
703/* */
704/* Utility functions to manage arrays and their contents for expansion */
705/* */
706/***********************************************************************/
707
708/* Return 1 if NAME is a properly-formed array reference v[sub]. */
709int
710valid_array_reference (name)
711 char *name;
712{
713 char *t;
714 int r, len;
715
7117c2d2 716 t = xstrchr (name, '['); /* ] */
f73dda09
JA
717 if (t)
718 {
719 *t = '\0';
720 r = legal_identifier (name);
721 *t = '[';
722 if (r == 0)
723 return 0;
724 /* Check for a properly-terminated non-blank subscript. */
725 len = skipsubscript (t, 0);
726 if (t[len] != ']' || len == 1)
727 return 0;
728 for (r = 1; r < len; r++)
729 if (whitespace (t[r]) == 0)
730 return 1;
731 return 0;
732 }
733 return 0;
734}
735
736/* Expand the array index beginning at S and extending LEN characters. */
737arrayind_t
738array_expand_index (s, len)
739 char *s;
740 int len;
741{
742 char *exp, *t;
743 int expok;
744 arrayind_t val;
745
746 exp = (char *)xmalloc (len);
747 strncpy (exp, s, len - 1);
748 exp[len - 1] = '\0';
0628567a 749 t = expand_arith_string (exp, 0);
f73dda09
JA
750 this_command_name = (char *)NULL;
751 val = evalexp (t, &expok);
752 free (t);
753 free (exp);
754 if (expok == 0)
755 {
756 last_command_exit_value = EXECUTION_FAILURE;
f1be666c
JA
757
758 top_level_cleanup ();
f73dda09
JA
759 jump_to_top_level (DISCARD);
760 }
761 return val;
762}
763
764/* Return the name of the variable specified by S without any subscript.
765 If SUBP is non-null, return a pointer to the start of the subscript
766 in *SUBP. If LENP is non-null, the length of the subscript is returned
767 in *LENP. This returns newly-allocated memory. */
768char *
769array_variable_name (s, subp, lenp)
770 char *s, **subp;
771 int *lenp;
772{
773 char *t, *ret;
774 int ind, ni;
775
7117c2d2 776 t = xstrchr (s, '[');
f73dda09 777 if (t == 0)
b80f6443
JA
778 {
779 if (subp)
780 *subp = t;
781 if (lenp)
782 *lenp = 0;
783 return ((char *)NULL);
784 }
f73dda09
JA
785 ind = t - s;
786 ni = skipsubscript (s, ind);
787 if (ni <= ind + 1 || s[ni] != ']')
788 {
7117c2d2 789 err_badarraysub (s);
b80f6443
JA
790 if (subp)
791 *subp = t;
792 if (lenp)
793 *lenp = 0;
f73dda09
JA
794 return ((char *)NULL);
795 }
796
797 *t = '\0';
798 ret = savestring (s);
799 *t++ = '['; /* ] */
800
801 if (subp)
802 *subp = t;
803 if (lenp)
804 *lenp = ni - ind;
805
806 return ret;
807}
808
809/* Return the variable specified by S without any subscript. If SUBP is
810 non-null, return a pointer to the start of the subscript in *SUBP.
811 If LENP is non-null, the length of the subscript is returned in *LENP. */
812SHELL_VAR *
813array_variable_part (s, subp, lenp)
814 char *s, **subp;
815 int *lenp;
816{
817 char *t;
818 SHELL_VAR *var;
819
820 t = array_variable_name (s, subp, lenp);
821 if (t == 0)
822 return ((SHELL_VAR *)NULL);
823 var = find_variable (t);
824
825 free (t);
eb873671 826 return (var == 0 || invisible_p (var)) ? (SHELL_VAR *)0 : var;
f73dda09
JA
827}
828
829/* Return a string containing the elements in the array and subscript
830 described by S. If the subscript is * or @, obeys quoting rules akin
7117c2d2 831 to the expansion of $* and $@ including double quoting. If RTYPE
3185942a
JA
832 is non-null it gets 1 if the array reference is name[*], 2 if the
833 reference is name[@], and 0 otherwise. */
f73dda09 834static char *
7117c2d2 835array_value_internal (s, quoted, allow_all, rtype)
f73dda09 836 char *s;
7117c2d2 837 int quoted, allow_all, *rtype;
f73dda09
JA
838{
839 int len;
840 arrayind_t ind;
3185942a 841 char *akey;
f73dda09
JA
842 char *retval, *t, *temp;
843 WORD_LIST *l;
844 SHELL_VAR *var;
845
846 var = array_variable_part (s, &t, &len);
847
7117c2d2
JA
848 /* Expand the index, even if the variable doesn't exist, in case side
849 effects are needed, like ${w[i++]} where w is unset. */
850#if 0
f73dda09
JA
851 if (var == 0)
852 return (char *)NULL;
7117c2d2 853#endif
f73dda09 854
b80f6443
JA
855 if (len == 0)
856 return ((char *)NULL); /* error message already printed */
857
f73dda09
JA
858 /* [ */
859 if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
860 {
7117c2d2 861 if (rtype)
f1be666c 862 *rtype = (t[0] == '*') ? 1 : 2;
f73dda09
JA
863 if (allow_all == 0)
864 {
7117c2d2 865 err_badarraysub (s);
f73dda09
JA
866 return ((char *)NULL);
867 }
95732b49 868 else if (var == 0 || value_cell (var) == 0)
7117c2d2 869 return ((char *)NULL);
3185942a 870 else if (array_p (var) == 0 && assoc_p (var) == 0)
7117c2d2 871 l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
3185942a
JA
872 else if (assoc_p (var))
873 {
874 l = assoc_to_word_list (assoc_cell (var));
875 if (l == (WORD_LIST *)NULL)
876 return ((char *)NULL);
877 }
f73dda09
JA
878 else
879 {
880 l = array_to_word_list (array_cell (var));
881 if (l == (WORD_LIST *)NULL)
882 return ((char *) NULL);
883 }
884
885 if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
886 {
887 temp = string_list_dollar_star (l);
888 retval = quote_string (temp);
889 free (temp);
890 }
891 else /* ${name[@]} or unquoted ${name[*]} */
892 retval = string_list_dollar_at (l, quoted);
893
894 dispose_words (l);
895 }
896 else
897 {
7117c2d2
JA
898 if (rtype)
899 *rtype = 0;
3185942a 900 if (var == 0 || array_p (var) || assoc_p (var) == 0)
f73dda09 901 {
3185942a
JA
902 ind = array_expand_index (t, len);
903 if (ind < 0)
7117c2d2 904 {
3185942a
JA
905index_error:
906 if (var)
907 err_badarraysub (var->name);
908 else
909 {
910 t[-1] = '\0';
911 err_badarraysub (s);
912 t[-1] = '['; /* ] */
913 }
914 return ((char *)NULL);
7117c2d2 915 }
f73dda09 916 }
3185942a
JA
917 else if (assoc_p (var))
918 {
919 t[len - 1] = '\0';
920 akey = expand_assignment_string_to_string (t, 0); /* [ */
921 t[len - 1] = ']';
922 if (akey == 0 || *akey == 0)
923 goto index_error;
924 }
925
7117c2d2
JA
926 if (var == 0)
927 return ((char *)NULL);
3185942a 928 if (array_p (var) == 0 && assoc_p (var) == 0)
7117c2d2 929 return (ind == 0 ? value_cell (var) : (char *)NULL);
3185942a
JA
930 else if (assoc_p (var))
931 retval = assoc_reference (assoc_cell (var), akey);
932 else
933 retval = array_reference (array_cell (var), ind);
f73dda09
JA
934 }
935
936 return retval;
937}
938
939/* Return a string containing the elements described by the array and
940 subscript contained in S, obeying quoting for subscripts * and @. */
941char *
7117c2d2 942array_value (s, quoted, rtype)
f73dda09 943 char *s;
7117c2d2 944 int quoted, *rtype;
f73dda09 945{
7117c2d2 946 return (array_value_internal (s, quoted, 1, rtype));
f73dda09
JA
947}
948
949/* Return the value of the array indexing expression S as a single string.
950 If ALLOW_ALL is 0, do not allow `@' and `*' subscripts. This is used
951 by other parts of the shell such as the arithmetic expression evaluator
952 in expr.c. */
953char *
7117c2d2 954get_array_value (s, allow_all, rtype)
f73dda09 955 char *s;
7117c2d2 956 int allow_all, *rtype;
f73dda09 957{
7117c2d2 958 return (array_value_internal (s, 0, allow_all, rtype));
f73dda09
JA
959}
960
b80f6443
JA
961char *
962array_keys (s, quoted)
963 char *s;
964 int quoted;
965{
966 int len;
967 char *retval, *t, *temp;
968 WORD_LIST *l;
969 SHELL_VAR *var;
970
971 var = array_variable_part (s, &t, &len);
972
973 /* [ */
974 if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']')
975 return (char *)NULL;
976
3185942a 977 if (array_p (var) == 0 && assoc_p (var) == 0)
b80f6443 978 l = add_string_to_list ("0", (WORD_LIST *)NULL);
3185942a
JA
979 else if (assoc_p (var))
980 l = assoc_keys_to_word_list (assoc_cell (var));
b80f6443 981 else
3185942a
JA
982 l = array_keys_to_word_list (array_cell (var));
983 if (l == (WORD_LIST *)NULL)
984 return ((char *) NULL);
b80f6443
JA
985
986 if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
987 {
988 temp = string_list_dollar_star (l);
989 retval = quote_string (temp);
990 free (temp);
991 }
992 else /* ${!name[@]} or unquoted ${!name[*]} */
993 retval = string_list_dollar_at (l, quoted);
994
995 dispose_words (l);
996 return retval;
997}
f73dda09 998#endif /* ARRAY_VARS */