]> git.ipfire.org Git - thirdparty/bash.git/blame - arrayfunc.c
Imported from ../bash-4.0.tar.gz.
[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)
101 assoc_insert (hash, "0", oldval);
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
607/* This function assumes s[i] == '['; returns with s[ret] == ']' if
608 an array subscript is correctly parsed. */
609int
610skipsubscript (s, i)
611 const char *s;
612 int i;
613{
614 int count, c;
7117c2d2
JA
615#if defined (HANDLE_MULTIBYTE)
616 mbstate_t state, state_bak;
617 size_t slength, mblength;
7117c2d2 618#endif
f73dda09 619
7117c2d2
JA
620#if defined (HANDLE_MULTIBYTE)
621 memset (&state, '\0', sizeof (mbstate_t));
622 slength = strlen (s + i);
7117c2d2
JA
623#endif
624
625 count = 1;
626 while (count)
f73dda09 627 {
7117c2d2
JA
628 /* Advance one (possibly multibyte) character in S starting at I. */
629#if defined (HANDLE_MULTIBYTE)
0628567a 630 if (MB_CUR_MAX > 1)
7117c2d2
JA
631 {
632 state_bak = state;
633 mblength = mbrlen (s + i, slength, &state);
634
b80f6443 635 if (MB_INVALIDCH (mblength))
7117c2d2
JA
636 {
637 state = state_bak;
638 i++;
639 slength--;
640 }
b80f6443 641 else if (MB_NULLWCH (mblength))
7117c2d2
JA
642 return i;
643 else
644 {
645 i += mblength;
646 slength -= mblength;
647 }
648 }
649 else
650#endif
651 ++i;
652
653 c = s[i];
654
655 if (c == 0)
3185942a 656 break;
7117c2d2 657 else if (c == '[')
f73dda09
JA
658 count++;
659 else if (c == ']')
660 count--;
661 }
7117c2d2 662
f73dda09
JA
663 return i;
664}
665
666/* This function is called with SUB pointing to just after the beginning
667 `[' of an array subscript and removes the array element to which SUB
668 expands from array VAR. A subscript of `*' or `@' unsets the array. */
669int
670unbind_array_element (var, sub)
671 SHELL_VAR *var;
672 char *sub;
673{
674 int len;
675 arrayind_t ind;
3185942a 676 char *akey;
f73dda09
JA
677 ARRAY_ELEMENT *ae;
678
679 len = skipsubscript (sub, 0);
680 if (sub[len] != ']' || len == 0)
681 {
b80f6443 682 builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg));
f73dda09
JA
683 return -1;
684 }
685 sub[len] = '\0';
686
687 if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0)
688 {
7117c2d2 689 unbind_variable (var->name);
f73dda09
JA
690 return (0);
691 }
3185942a
JA
692
693 if (assoc_p (var))
f73dda09 694 {
3185942a
JA
695 akey = expand_assignment_string_to_string (sub, 0); /* [ */
696 if (akey == 0 || *akey == 0)
697 {
698 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
699 return -1;
700 }
701 assoc_remove (assoc_cell (var), akey);
702 }
703 else
704 {
705 ind = array_expand_index (sub, len+1);
706 if (ind < 0)
707 {
708 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
709 return -1;
710 }
711 ae = array_remove (array_cell (var), ind);
712 if (ae)
713 array_dispose_element (ae);
f73dda09 714 }
3185942a 715
f73dda09
JA
716 return 0;
717}
718
719/* Format and output an array assignment in compound form VAR=(VALUES),
720 suitable for re-use as input. */
721void
722print_array_assignment (var, quoted)
723 SHELL_VAR *var;
724 int quoted;
725{
726 char *vstr;
727
7117c2d2 728 vstr = array_to_assign (array_cell (var), quoted);
f73dda09
JA
729
730 if (vstr == 0)
731 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
732 else
733 {
734 printf ("%s=%s\n", var->name, vstr);
735 free (vstr);
736 }
737}
738
3185942a
JA
739/* Format and output an associative array assignment in compound form
740 VAR=(VALUES), suitable for re-use as input. */
741void
742print_assoc_assignment (var, quoted)
743 SHELL_VAR *var;
744 int quoted;
745{
746 char *vstr;
747
748 vstr = assoc_to_assign (assoc_cell (var), quoted);
749
750 if (vstr == 0)
751 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
752 else
753 {
754 printf ("%s=%s\n", var->name, vstr);
755 free (vstr);
756 }
757}
758
f73dda09
JA
759/***********************************************************************/
760/* */
761/* Utility functions to manage arrays and their contents for expansion */
762/* */
763/***********************************************************************/
764
765/* Return 1 if NAME is a properly-formed array reference v[sub]. */
766int
767valid_array_reference (name)
768 char *name;
769{
770 char *t;
771 int r, len;
772
7117c2d2 773 t = xstrchr (name, '['); /* ] */
f73dda09
JA
774 if (t)
775 {
776 *t = '\0';
777 r = legal_identifier (name);
778 *t = '[';
779 if (r == 0)
780 return 0;
781 /* Check for a properly-terminated non-blank subscript. */
782 len = skipsubscript (t, 0);
783 if (t[len] != ']' || len == 1)
784 return 0;
785 for (r = 1; r < len; r++)
786 if (whitespace (t[r]) == 0)
787 return 1;
788 return 0;
789 }
790 return 0;
791}
792
793/* Expand the array index beginning at S and extending LEN characters. */
794arrayind_t
795array_expand_index (s, len)
796 char *s;
797 int len;
798{
799 char *exp, *t;
800 int expok;
801 arrayind_t val;
802
803 exp = (char *)xmalloc (len);
804 strncpy (exp, s, len - 1);
805 exp[len - 1] = '\0';
0628567a 806 t = expand_arith_string (exp, 0);
f73dda09
JA
807 this_command_name = (char *)NULL;
808 val = evalexp (t, &expok);
809 free (t);
810 free (exp);
811 if (expok == 0)
812 {
813 last_command_exit_value = EXECUTION_FAILURE;
f1be666c
JA
814
815 top_level_cleanup ();
f73dda09
JA
816 jump_to_top_level (DISCARD);
817 }
818 return val;
819}
820
821/* Return the name of the variable specified by S without any subscript.
822 If SUBP is non-null, return a pointer to the start of the subscript
823 in *SUBP. If LENP is non-null, the length of the subscript is returned
824 in *LENP. This returns newly-allocated memory. */
825char *
826array_variable_name (s, subp, lenp)
827 char *s, **subp;
828 int *lenp;
829{
830 char *t, *ret;
831 int ind, ni;
832
7117c2d2 833 t = xstrchr (s, '[');
f73dda09 834 if (t == 0)
b80f6443
JA
835 {
836 if (subp)
837 *subp = t;
838 if (lenp)
839 *lenp = 0;
840 return ((char *)NULL);
841 }
f73dda09
JA
842 ind = t - s;
843 ni = skipsubscript (s, ind);
844 if (ni <= ind + 1 || s[ni] != ']')
845 {
7117c2d2 846 err_badarraysub (s);
b80f6443
JA
847 if (subp)
848 *subp = t;
849 if (lenp)
850 *lenp = 0;
f73dda09
JA
851 return ((char *)NULL);
852 }
853
854 *t = '\0';
855 ret = savestring (s);
856 *t++ = '['; /* ] */
857
858 if (subp)
859 *subp = t;
860 if (lenp)
861 *lenp = ni - ind;
862
863 return ret;
864}
865
866/* Return the variable specified by S without any subscript. If SUBP is
867 non-null, return a pointer to the start of the subscript in *SUBP.
868 If LENP is non-null, the length of the subscript is returned in *LENP. */
869SHELL_VAR *
870array_variable_part (s, subp, lenp)
871 char *s, **subp;
872 int *lenp;
873{
874 char *t;
875 SHELL_VAR *var;
876
877 t = array_variable_name (s, subp, lenp);
878 if (t == 0)
879 return ((SHELL_VAR *)NULL);
880 var = find_variable (t);
881
882 free (t);
eb873671 883 return (var == 0 || invisible_p (var)) ? (SHELL_VAR *)0 : var;
f73dda09
JA
884}
885
886/* Return a string containing the elements in the array and subscript
887 described by S. If the subscript is * or @, obeys quoting rules akin
7117c2d2 888 to the expansion of $* and $@ including double quoting. If RTYPE
3185942a
JA
889 is non-null it gets 1 if the array reference is name[*], 2 if the
890 reference is name[@], and 0 otherwise. */
f73dda09 891static char *
7117c2d2 892array_value_internal (s, quoted, allow_all, rtype)
f73dda09 893 char *s;
7117c2d2 894 int quoted, allow_all, *rtype;
f73dda09
JA
895{
896 int len;
897 arrayind_t ind;
3185942a 898 char *akey;
f73dda09
JA
899 char *retval, *t, *temp;
900 WORD_LIST *l;
901 SHELL_VAR *var;
902
903 var = array_variable_part (s, &t, &len);
904
7117c2d2
JA
905 /* Expand the index, even if the variable doesn't exist, in case side
906 effects are needed, like ${w[i++]} where w is unset. */
907#if 0
f73dda09
JA
908 if (var == 0)
909 return (char *)NULL;
7117c2d2 910#endif
f73dda09 911
b80f6443
JA
912 if (len == 0)
913 return ((char *)NULL); /* error message already printed */
914
f73dda09
JA
915 /* [ */
916 if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
917 {
7117c2d2 918 if (rtype)
f1be666c 919 *rtype = (t[0] == '*') ? 1 : 2;
f73dda09
JA
920 if (allow_all == 0)
921 {
7117c2d2 922 err_badarraysub (s);
f73dda09
JA
923 return ((char *)NULL);
924 }
95732b49 925 else if (var == 0 || value_cell (var) == 0)
7117c2d2 926 return ((char *)NULL);
3185942a 927 else if (array_p (var) == 0 && assoc_p (var) == 0)
7117c2d2 928 l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
3185942a
JA
929 else if (assoc_p (var))
930 {
931 l = assoc_to_word_list (assoc_cell (var));
932 if (l == (WORD_LIST *)NULL)
933 return ((char *)NULL);
934 }
f73dda09
JA
935 else
936 {
937 l = array_to_word_list (array_cell (var));
938 if (l == (WORD_LIST *)NULL)
939 return ((char *) NULL);
940 }
941
942 if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
943 {
944 temp = string_list_dollar_star (l);
945 retval = quote_string (temp);
946 free (temp);
947 }
948 else /* ${name[@]} or unquoted ${name[*]} */
949 retval = string_list_dollar_at (l, quoted);
950
951 dispose_words (l);
952 }
953 else
954 {
7117c2d2
JA
955 if (rtype)
956 *rtype = 0;
3185942a 957 if (var == 0 || array_p (var) || assoc_p (var) == 0)
f73dda09 958 {
3185942a
JA
959 ind = array_expand_index (t, len);
960 if (ind < 0)
7117c2d2 961 {
3185942a
JA
962index_error:
963 if (var)
964 err_badarraysub (var->name);
965 else
966 {
967 t[-1] = '\0';
968 err_badarraysub (s);
969 t[-1] = '['; /* ] */
970 }
971 return ((char *)NULL);
7117c2d2 972 }
f73dda09 973 }
3185942a
JA
974 else if (assoc_p (var))
975 {
976 t[len - 1] = '\0';
977 akey = expand_assignment_string_to_string (t, 0); /* [ */
978 t[len - 1] = ']';
979 if (akey == 0 || *akey == 0)
980 goto index_error;
981 }
982
7117c2d2
JA
983 if (var == 0)
984 return ((char *)NULL);
3185942a 985 if (array_p (var) == 0 && assoc_p (var) == 0)
7117c2d2 986 return (ind == 0 ? value_cell (var) : (char *)NULL);
3185942a
JA
987 else if (assoc_p (var))
988 retval = assoc_reference (assoc_cell (var), akey);
989 else
990 retval = array_reference (array_cell (var), ind);
f73dda09
JA
991 }
992
993 return retval;
994}
995
996/* Return a string containing the elements described by the array and
997 subscript contained in S, obeying quoting for subscripts * and @. */
998char *
7117c2d2 999array_value (s, quoted, rtype)
f73dda09 1000 char *s;
7117c2d2 1001 int quoted, *rtype;
f73dda09 1002{
7117c2d2 1003 return (array_value_internal (s, quoted, 1, rtype));
f73dda09
JA
1004}
1005
1006/* Return the value of the array indexing expression S as a single string.
1007 If ALLOW_ALL is 0, do not allow `@' and `*' subscripts. This is used
1008 by other parts of the shell such as the arithmetic expression evaluator
1009 in expr.c. */
1010char *
7117c2d2 1011get_array_value (s, allow_all, rtype)
f73dda09 1012 char *s;
7117c2d2 1013 int allow_all, *rtype;
f73dda09 1014{
7117c2d2 1015 return (array_value_internal (s, 0, allow_all, rtype));
f73dda09
JA
1016}
1017
b80f6443
JA
1018char *
1019array_keys (s, quoted)
1020 char *s;
1021 int quoted;
1022{
1023 int len;
1024 char *retval, *t, *temp;
1025 WORD_LIST *l;
1026 SHELL_VAR *var;
1027
1028 var = array_variable_part (s, &t, &len);
1029
1030 /* [ */
1031 if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']')
1032 return (char *)NULL;
1033
3185942a 1034 if (array_p (var) == 0 && assoc_p (var) == 0)
b80f6443 1035 l = add_string_to_list ("0", (WORD_LIST *)NULL);
3185942a
JA
1036 else if (assoc_p (var))
1037 l = assoc_keys_to_word_list (assoc_cell (var));
b80f6443 1038 else
3185942a
JA
1039 l = array_keys_to_word_list (array_cell (var));
1040 if (l == (WORD_LIST *)NULL)
1041 return ((char *) NULL);
b80f6443
JA
1042
1043 if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
1044 {
1045 temp = string_list_dollar_star (l);
1046 retval = quote_string (temp);
1047 free (temp);
1048 }
1049 else /* ${!name[@]} or unquoted ${!name[*]} */
1050 retval = string_list_dollar_at (l, quoted);
1051
1052 dispose_words (l);
1053 return retval;
1054}
f73dda09 1055#endif /* ARRAY_VARS */