]> git.ipfire.org Git - thirdparty/bash.git/blame - arrayfunc.c
commit bash-20080605 snapshot
[thirdparty/bash.git] / arrayfunc.c
CommitLineData
f73dda09
JA
1/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
2
d3ad40de 3/* Copyright (C) 2001-2006 Free Software Foundation, Inc.
f73dda09
JA
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
7 Bash is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with Bash; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
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
5e13499c
CR
30#include "bashintl.h"
31
f73dda09 32#include "shell.h"
7117c2d2
JA
33
34#include "shmbutil.h"
35
f73dda09
JA
36#include "builtins/common.h"
37
38extern char *this_command_name;
39extern int last_command_exit_value;
633e5c6d 40extern int array_needs_making;
f73dda09 41
d11b8b46
CR
42static SHELL_VAR *bind_array_var_internal __P((SHELL_VAR *, arrayind_t, char *, int));
43
4ac1ff98 44static char *quote_assign __P((const char *));
f73dda09 45static void quote_array_assignment_chars __P((WORD_LIST *));
7117c2d2 46static char *array_value_internal __P((char *, int, int, int *));
f73dda09 47
5e13499c 48/* Standard error message to use when encountering an invalid array subscript */
d3ad40de 49const char * const bash_badsub_errmsg = N_("bad array subscript");
5e13499c 50
f73dda09
JA
51/* **************************************************************** */
52/* */
53/* Functions to manipulate array variables and perform assignments */
54/* */
55/* **************************************************************** */
56
57/* Convert a shell variable to an array variable. The original value is
58 saved as array[0]. */
59SHELL_VAR *
60convert_var_to_array (var)
61 SHELL_VAR *var;
62{
63 char *oldval;
64 ARRAY *array;
65
66 oldval = value_cell (var);
7117c2d2 67 array = array_create ();
d3a24ed2
CR
68 if (oldval)
69 array_insert (array, 0, oldval);
f73dda09
JA
70
71 FREE (value_cell (var));
7117c2d2
JA
72 var_setarray (var, array);
73
74 /* these aren't valid anymore */
75 var->dynamic_value = (sh_var_value_func_t *)NULL;
76 var->assign_func = (sh_var_assign_func_t *)NULL;
f73dda09
JA
77
78 INVALIDATE_EXPORTSTR (var);
633e5c6d
CR
79 if (exported_p (var))
80 array_needs_making++;
f73dda09
JA
81
82 VSETATTR (var, att_array);
83 VUNSETATTR (var, att_invisible);
84
85 return var;
86}
87
d11b8b46
CR
88static SHELL_VAR *
89bind_array_var_internal (entry, ind, value, flags)
90 SHELL_VAR *entry;
91 arrayind_t ind;
92 char *value;
93 int flags;
94{
95 SHELL_VAR *dentry;
96 char *newval;
97
98 /* If we're appending, we need the old value of the array reference, so
99 fake out make_variable_value with a dummy SHELL_VAR */
100 if (flags & ASS_APPEND)
101 {
102 dentry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
103 dentry->name = savestring (entry->name);
104 newval = array_reference (array_cell (entry), ind);
105 if (newval)
106 dentry->value = savestring (newval);
107 else
108 {
109 dentry->value = (char *)xmalloc (1);
110 dentry->value[0] = '\0';
111 }
112 dentry->exportstr = 0;
113 dentry->attributes = entry->attributes & ~(att_array|att_exported);
114 /* Leave the rest of the members uninitialized; the code doesn't look
115 at them. */
116 newval = make_variable_value (dentry, value, flags);
117 dispose_variable (dentry);
118 }
119 else
120 newval = make_variable_value (entry, value, flags);
121
122 if (entry->assign_func)
123 (*entry->assign_func) (entry, newval, ind);
124 else
125 array_insert (array_cell (entry), ind, newval);
126 FREE (newval);
127
128 return (entry);
129}
130
f73dda09
JA
131/* Perform an array assignment name[ind]=value. If NAME already exists and
132 is not an array, and IND is 0, perform name=value instead. If NAME exists
133 and is not an array, and IND is not 0, convert it into an array with the
134 existing value as name[0].
135
136 If NAME does not exist, just create an array variable, no matter what
137 IND's value may be. */
138SHELL_VAR *
d11b8b46 139bind_array_variable (name, ind, value, flags)
f73dda09
JA
140 char *name;
141 arrayind_t ind;
142 char *value;
d11b8b46 143 int flags;
f73dda09
JA
144{
145 SHELL_VAR *entry;
f73dda09
JA
146
147 entry = var_lookup (name, shell_variables);
148
149 if (entry == (SHELL_VAR *) 0)
150 entry = make_new_array_variable (name);
151 else if (readonly_p (entry) || noassign_p (entry))
152 {
153 if (readonly_p (entry))
7117c2d2 154 err_readonly (name);
f73dda09
JA
155 return (entry);
156 }
157 else if (array_p (entry) == 0)
158 entry = convert_var_to_array (entry);
159
160 /* ENTRY is an array variable, and ARRAY points to the value. */
d11b8b46 161 return (bind_array_var_internal (entry, ind, value, flags));
f73dda09
JA
162}
163
6a8fd0ed
CR
164SHELL_VAR *
165bind_array_element (entry, ind, value, flags)
166 SHELL_VAR *entry;
167 arrayind_t ind;
168 char *value;
169 int flags;
170{
171 return (bind_array_var_internal (entry, ind, value, flags));
172}
173
f73dda09
JA
174/* Parse NAME, a lhs of an assignment statement of the form v[s], and
175 assign VALUE to that array element by calling bind_array_variable(). */
176SHELL_VAR *
d11b8b46 177assign_array_element (name, value, flags)
f73dda09 178 char *name, *value;
d11b8b46 179 int flags;
f73dda09
JA
180{
181 char *sub, *vname;
182 arrayind_t ind;
183 int sublen;
184 SHELL_VAR *entry;
185
186 vname = array_variable_name (name, &sub, &sublen);
187
188 if (vname == 0)
189 return ((SHELL_VAR *)NULL);
190
191 if ((ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']') || (sublen <= 1))
192 {
193 free (vname);
7117c2d2 194 err_badarraysub (name);
f73dda09
JA
195 return ((SHELL_VAR *)NULL);
196 }
197
198 ind = array_expand_index (sub, sublen);
199 if (ind < 0)
200 {
201 free (vname);
7117c2d2 202 err_badarraysub (name);
f73dda09
JA
203 return ((SHELL_VAR *)NULL);
204 }
205
d11b8b46 206 entry = bind_array_variable (vname, ind, value, flags);
f73dda09
JA
207
208 free (vname);
209 return (entry);
210}
211
212/* Find the array variable corresponding to NAME. If there is no variable,
213 create a new array variable. If the variable exists but is not an array,
214 convert it to an indexed array. If CHECK_FLAGS is non-zero, an existing
215 variable is checked for the readonly or noassign attribute in preparation
216 for assignment (e.g., by the `read' builtin). */
217SHELL_VAR *
218find_or_make_array_variable (name, check_flags)
219 char *name;
220 int check_flags;
221{
222 SHELL_VAR *var;
223
224 var = find_variable (name);
225
226 if (var == 0)
227 var = make_new_array_variable (name);
228 else if (check_flags && (readonly_p (var) || noassign_p (var)))
229 {
230 if (readonly_p (var))
7117c2d2 231 err_readonly (name);
f73dda09
JA
232 return ((SHELL_VAR *)NULL);
233 }
234 else if (array_p (var) == 0)
235 var = convert_var_to_array (var);
236
237 return (var);
238}
239
240/* Perform a compound assignment statement for array NAME, where VALUE is
241 the text between the parens: NAME=( VALUE ) */
242SHELL_VAR *
d11b8b46 243assign_array_from_string (name, value, flags)
f73dda09 244 char *name, *value;
d11b8b46 245 int flags;
f73dda09
JA
246{
247 SHELL_VAR *var;
248
249 var = find_or_make_array_variable (name, 1);
250 if (var == 0)
251 return ((SHELL_VAR *)NULL);
252
d11b8b46 253 return (assign_array_var_from_string (var, value, flags));
f73dda09
JA
254}
255
256/* Sequentially assign the indices of indexed array variable VAR from the
257 words in LIST. */
258SHELL_VAR *
d11b8b46 259assign_array_var_from_word_list (var, list, flags)
f73dda09
JA
260 SHELL_VAR *var;
261 WORD_LIST *list;
d11b8b46 262 int flags;
f73dda09
JA
263{
264 register arrayind_t i;
265 register WORD_LIST *l;
266 ARRAY *a;
267
d11b8b46
CR
268 a = array_cell (var);
269 i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
270
271 for (l = list; l; l = l->next, i++)
f73dda09 272 if (var->assign_func)
7117c2d2 273 (*var->assign_func) (var, l->word->word, i);
f73dda09 274 else
7117c2d2 275 array_insert (a, i, l->word->word);
f73dda09
JA
276 return var;
277}
278
d3ad40de
CR
279WORD_LIST *
280expand_compound_array_assignment (value, flags)
f73dda09 281 char *value;
d11b8b46 282 int flags;
f73dda09 283{
f73dda09 284 WORD_LIST *list, *nlist;
d3ad40de
CR
285 char *val;
286 int ni;
f73dda09 287
d3ad40de 288 /* I don't believe this condition is ever true any more. */
f73dda09
JA
289 if (*value == '(') /*)*/
290 {
291 ni = 1;
292 val = extract_array_assignment_list (value, &ni);
293 if (val == 0)
d3ad40de 294 return (WORD_LIST *)NULL;
f73dda09
JA
295 }
296 else
297 val = value;
298
299 /* Expand the value string into a list of words, performing all the
300 shell expansions including pathname generation and word splitting. */
301 /* First we split the string on whitespace, using the shell parser
302 (ksh93 seems to do this). */
5e13499c 303 list = parse_string_to_word_list (val, 1, "array assign");
f73dda09
JA
304
305 /* If we're using [subscript]=value, we need to quote each [ and ] to
306 prevent unwanted filename expansion. */
307 if (list)
308 quote_array_assignment_chars (list);
309
310 /* Now that we've split it, perform the shell expansions on each
311 word in the list. */
312 nlist = list ? expand_words_no_vars (list) : (WORD_LIST *)NULL;
313
314 dispose_words (list);
315
316 if (val != value)
317 free (val);
318
d3ad40de
CR
319 return nlist;
320}
321
322void
323assign_compound_array_list (var, nlist, flags)
324 SHELL_VAR *var;
325 WORD_LIST *nlist;
326 int flags;
327{
328 ARRAY *a;
329 WORD_LIST *list;
330 char *w, *val, *nval;
331 int len, iflags;
332 arrayind_t ind, last_ind;
333
f73dda09
JA
334 a = array_cell (var);
335
336 /* Now that we are ready to assign values to the array, kill the existing
337 value. */
d11b8b46 338 if (a && (flags & ASS_APPEND) == 0)
7117c2d2 339 array_flush (a);
d11b8b46 340 last_ind = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
f73dda09 341
d11b8b46 342 for (list = nlist; list; list = list->next)
f73dda09 343 {
d3ad40de 344 iflags = flags;
f73dda09
JA
345 w = list->word->word;
346
347 /* We have a word of the form [ind]=value */
5e13499c 348 if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
f73dda09
JA
349 {
350 len = skipsubscript (w, 0);
351
d11b8b46
CR
352 /* XXX - changes for `+=' */
353 if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
f73dda09 354 {
d11b8b46 355 nval = make_variable_value (var, w, flags);
f73dda09 356 if (var->assign_func)
7117c2d2 357 (*var->assign_func) (var, nval, last_ind);
f73dda09 358 else
7117c2d2 359 array_insert (a, last_ind, nval);
f73dda09
JA
360 FREE (nval);
361 last_ind++;
362 continue;
363 }
364
365 if (len == 1)
366 {
7117c2d2 367 err_badarraysub (w);
f73dda09
JA
368 continue;
369 }
370
371 if (ALL_ELEMENT_SUB (w[1]) && len == 2)
372 {
5e13499c 373 report_error (_("%s: cannot assign to non-numeric index"), w);
f73dda09
JA
374 continue;
375 }
376
377 ind = array_expand_index (w + 1, len);
378 if (ind < 0)
379 {
7117c2d2 380 err_badarraysub (w);
f73dda09
JA
381 continue;
382 }
383 last_ind = ind;
d3ad40de 384 /* XXX - changes for `+=' -- just accept the syntax. ksh93 doesn't do this */
d11b8b46
CR
385 if (w[len + 1] == '+' && w[len + 2] == '=')
386 {
d3ad40de 387 iflags |= ASS_APPEND;
d11b8b46
CR
388 val = w + len + 3;
389 }
390 else
391 val = w + len + 2;
f73dda09
JA
392 }
393 else /* No [ind]=value, just a stray `=' */
394 {
395 ind = last_ind;
396 val = w;
397 }
398
399 if (integer_p (var))
400 this_command_name = (char *)NULL; /* no command name for errors */
d3ad40de 401 bind_array_var_internal (var, ind, val, iflags);
f73dda09
JA
402 last_ind++;
403 }
d3ad40de
CR
404}
405
406/* Perform a compound array assignment: VAR->name=( VALUE ). The
407 VALUE has already had the parentheses stripped. */
408SHELL_VAR *
409assign_array_var_from_string (var, value, flags)
410 SHELL_VAR *var;
411 char *value;
412 int flags;
413{
414 WORD_LIST *nlist;
415
416 if (value == 0)
417 return var;
418
419 nlist = expand_compound_array_assignment (value, flags);
420 assign_compound_array_list (var, nlist, flags);
f73dda09 421
d3ad40de
CR
422 if (nlist)
423 dispose_words (nlist);
f73dda09
JA
424 return (var);
425}
426
4ac1ff98
CR
427static char *
428quote_assign (string)
429 const char *string;
430{
431 size_t slen;
432 int saw_eq;
433 char *temp, *t;
434 const char *s, *send;
435 DECLARE_MBSTATE;
436
437 slen = strlen (string);
438 send = string + slen;
439
440 t = temp = (char *)xmalloc (slen * 2 + 1);
441 saw_eq = 0;
442 for (s = string; *s; )
443 {
444 if (*s == '=')
445 saw_eq = 1;
446 if (saw_eq == 0 && (glob_char_p (s) || isifs (*s)))
447 *t++ = '\\';
448
449 COPY_CHAR_P (t, s, send);
450 }
451 *t = '\0';
452 return temp;
453}
454
f73dda09
JA
455/* For each word in a compound array assignment, if the word looks like
456 [ind]=value, quote the `[' and `]' before the `=' to protect them from
457 unwanted filename expansion. */
458static void
459quote_array_assignment_chars (list)
460 WORD_LIST *list;
461{
4ac1ff98 462 char *nword;
f73dda09
JA
463 WORD_LIST *l;
464
465 for (l = list; l; l = l->next)
466 {
467 if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
468 continue; /* should not happen, but just in case... */
469 /* Don't bother if it doesn't look like [ind]=value */
7117c2d2 470 if (l->word->word[0] != '[' || xstrchr (l->word->word, '=') == 0) /* ] */
f73dda09 471 continue;
4ac1ff98 472 nword = quote_assign (l->word->word);
f73dda09
JA
473 free (l->word->word);
474 l->word->word = nword;
475 }
476}
477
478/* This function assumes s[i] == '['; returns with s[ret] == ']' if
479 an array subscript is correctly parsed. */
480int
481skipsubscript (s, i)
482 const char *s;
483 int i;
484{
485 int count, c;
7117c2d2
JA
486#if defined (HANDLE_MULTIBYTE)
487 mbstate_t state, state_bak;
488 size_t slength, mblength;
7117c2d2 489#endif
f73dda09 490
7117c2d2
JA
491#if defined (HANDLE_MULTIBYTE)
492 memset (&state, '\0', sizeof (mbstate_t));
493 slength = strlen (s + i);
7117c2d2
JA
494#endif
495
496 count = 1;
497 while (count)
f73dda09 498 {
7117c2d2
JA
499 /* Advance one (possibly multibyte) character in S starting at I. */
500#if defined (HANDLE_MULTIBYTE)
dc8fbaf9 501 if (MB_CUR_MAX > 1)
7117c2d2
JA
502 {
503 state_bak = state;
504 mblength = mbrlen (s + i, slength, &state);
505
d3a24ed2 506 if (MB_INVALIDCH (mblength))
7117c2d2
JA
507 {
508 state = state_bak;
509 i++;
510 slength--;
511 }
d3a24ed2 512 else if (MB_NULLWCH (mblength))
7117c2d2
JA
513 return i;
514 else
515 {
516 i += mblength;
517 slength -= mblength;
518 }
519 }
520 else
521#endif
522 ++i;
523
524 c = s[i];
525
526 if (c == 0)
527 break;
528 else if (c == '[')
f73dda09
JA
529 count++;
530 else if (c == ']')
531 count--;
532 }
7117c2d2 533
f73dda09
JA
534 return i;
535}
536
537/* This function is called with SUB pointing to just after the beginning
538 `[' of an array subscript and removes the array element to which SUB
539 expands from array VAR. A subscript of `*' or `@' unsets the array. */
540int
541unbind_array_element (var, sub)
542 SHELL_VAR *var;
543 char *sub;
544{
545 int len;
546 arrayind_t ind;
547 ARRAY_ELEMENT *ae;
548
549 len = skipsubscript (sub, 0);
550 if (sub[len] != ']' || len == 0)
551 {
5e13499c 552 builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg));
f73dda09
JA
553 return -1;
554 }
555 sub[len] = '\0';
556
557 if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0)
558 {
7117c2d2 559 unbind_variable (var->name);
f73dda09
JA
560 return (0);
561 }
562 ind = array_expand_index (sub, len+1);
563 if (ind < 0)
564 {
5e13499c 565 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
f73dda09
JA
566 return -1;
567 }
7117c2d2 568 ae = array_remove (array_cell (var), ind);
f73dda09 569 if (ae)
7117c2d2 570 array_dispose_element (ae);
f73dda09
JA
571 return 0;
572}
573
574/* Format and output an array assignment in compound form VAR=(VALUES),
575 suitable for re-use as input. */
576void
577print_array_assignment (var, quoted)
578 SHELL_VAR *var;
579 int quoted;
580{
581 char *vstr;
582
7117c2d2 583 vstr = array_to_assign (array_cell (var), quoted);
f73dda09
JA
584
585 if (vstr == 0)
586 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
587 else
588 {
589 printf ("%s=%s\n", var->name, vstr);
590 free (vstr);
591 }
592}
593
594/***********************************************************************/
595/* */
596/* Utility functions to manage arrays and their contents for expansion */
597/* */
598/***********************************************************************/
599
600/* Return 1 if NAME is a properly-formed array reference v[sub]. */
601int
602valid_array_reference (name)
603 char *name;
604{
605 char *t;
606 int r, len;
607
7117c2d2 608 t = xstrchr (name, '['); /* ] */
f73dda09
JA
609 if (t)
610 {
611 *t = '\0';
612 r = legal_identifier (name);
613 *t = '[';
614 if (r == 0)
615 return 0;
616 /* Check for a properly-terminated non-blank subscript. */
617 len = skipsubscript (t, 0);
618 if (t[len] != ']' || len == 1)
619 return 0;
620 for (r = 1; r < len; r++)
621 if (whitespace (t[r]) == 0)
622 return 1;
623 return 0;
624 }
625 return 0;
626}
627
628/* Expand the array index beginning at S and extending LEN characters. */
629arrayind_t
630array_expand_index (s, len)
631 char *s;
632 int len;
633{
634 char *exp, *t;
635 int expok;
636 arrayind_t val;
637
638 exp = (char *)xmalloc (len);
639 strncpy (exp, s, len - 1);
640 exp[len - 1] = '\0';
d3ad40de 641 t = expand_arith_string (exp, 0);
f73dda09
JA
642 this_command_name = (char *)NULL;
643 val = evalexp (t, &expok);
644 free (t);
645 free (exp);
646 if (expok == 0)
647 {
648 last_command_exit_value = EXECUTION_FAILURE;
c184f645
CR
649
650 top_level_cleanup ();
f73dda09
JA
651 jump_to_top_level (DISCARD);
652 }
653 return val;
654}
655
656/* Return the name of the variable specified by S without any subscript.
657 If SUBP is non-null, return a pointer to the start of the subscript
658 in *SUBP. If LENP is non-null, the length of the subscript is returned
659 in *LENP. This returns newly-allocated memory. */
660char *
661array_variable_name (s, subp, lenp)
662 char *s, **subp;
663 int *lenp;
664{
665 char *t, *ret;
666 int ind, ni;
667
7117c2d2 668 t = xstrchr (s, '[');
f73dda09 669 if (t == 0)
5e13499c
CR
670 {
671 if (subp)
672 *subp = t;
673 if (lenp)
674 *lenp = 0;
675 return ((char *)NULL);
676 }
f73dda09
JA
677 ind = t - s;
678 ni = skipsubscript (s, ind);
679 if (ni <= ind + 1 || s[ni] != ']')
680 {
7117c2d2 681 err_badarraysub (s);
5e13499c
CR
682 if (subp)
683 *subp = t;
684 if (lenp)
685 *lenp = 0;
f73dda09
JA
686 return ((char *)NULL);
687 }
688
689 *t = '\0';
690 ret = savestring (s);
691 *t++ = '['; /* ] */
692
693 if (subp)
694 *subp = t;
695 if (lenp)
696 *lenp = ni - ind;
697
698 return ret;
699}
700
701/* Return the variable specified by S without any subscript. If SUBP is
702 non-null, return a pointer to the start of the subscript in *SUBP.
703 If LENP is non-null, the length of the subscript is returned in *LENP. */
704SHELL_VAR *
705array_variable_part (s, subp, lenp)
706 char *s, **subp;
707 int *lenp;
708{
709 char *t;
710 SHELL_VAR *var;
711
712 t = array_variable_name (s, subp, lenp);
713 if (t == 0)
714 return ((SHELL_VAR *)NULL);
715 var = find_variable (t);
716
717 free (t);
898cc92e 718 return (var == 0 || invisible_p (var)) ? (SHELL_VAR *)0 : var;
f73dda09
JA
719}
720
721/* Return a string containing the elements in the array and subscript
722 described by S. If the subscript is * or @, obeys quoting rules akin
7117c2d2 723 to the expansion of $* and $@ including double quoting. If RTYPE
b1a26c01
CR
724 is non-null it gets 1 if the array reference is name[*], 2 if the
725 reference is name[@], and 0 otherwise. */
f73dda09 726static char *
7117c2d2 727array_value_internal (s, quoted, allow_all, rtype)
f73dda09 728 char *s;
7117c2d2 729 int quoted, allow_all, *rtype;
f73dda09
JA
730{
731 int len;
732 arrayind_t ind;
733 char *retval, *t, *temp;
734 WORD_LIST *l;
735 SHELL_VAR *var;
736
737 var = array_variable_part (s, &t, &len);
738
7117c2d2
JA
739 /* Expand the index, even if the variable doesn't exist, in case side
740 effects are needed, like ${w[i++]} where w is unset. */
741#if 0
f73dda09
JA
742 if (var == 0)
743 return (char *)NULL;
7117c2d2 744#endif
f73dda09 745
d3a24ed2
CR
746 if (len == 0)
747 return ((char *)NULL); /* error message already printed */
748
f73dda09
JA
749 /* [ */
750 if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
751 {
7117c2d2 752 if (rtype)
b1a26c01 753 *rtype = (t[0] == '*') ? 1 : 2;
f73dda09
JA
754 if (allow_all == 0)
755 {
7117c2d2 756 err_badarraysub (s);
f73dda09
JA
757 return ((char *)NULL);
758 }
10590446 759 else if (var == 0 || value_cell (var) == 0)
7117c2d2 760 return ((char *)NULL);
f73dda09 761 else if (array_p (var) == 0)
7117c2d2 762 l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
f73dda09
JA
763 else
764 {
765 l = array_to_word_list (array_cell (var));
766 if (l == (WORD_LIST *)NULL)
767 return ((char *) NULL);
768 }
769
770 if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
771 {
772 temp = string_list_dollar_star (l);
773 retval = quote_string (temp);
774 free (temp);
775 }
776 else /* ${name[@]} or unquoted ${name[*]} */
777 retval = string_list_dollar_at (l, quoted);
778
779 dispose_words (l);
780 }
781 else
782 {
7117c2d2
JA
783 if (rtype)
784 *rtype = 0;
f73dda09
JA
785 ind = array_expand_index (t, len);
786 if (ind < 0)
787 {
7117c2d2
JA
788 if (var)
789 err_badarraysub (var->name);
790 else
791 {
792 t[-1] = '\0';
793 err_badarraysub (s);
794 t[-1] = '['; /* ] */
795 }
f73dda09
JA
796 return ((char *)NULL);
797 }
7117c2d2
JA
798 if (var == 0)
799 return ((char *)NULL);
f73dda09 800 if (array_p (var) == 0)
7117c2d2 801 return (ind == 0 ? value_cell (var) : (char *)NULL);
f73dda09 802 retval = array_reference (array_cell (var), ind);
f73dda09
JA
803 }
804
805 return retval;
806}
807
808/* Return a string containing the elements described by the array and
809 subscript contained in S, obeying quoting for subscripts * and @. */
810char *
7117c2d2 811array_value (s, quoted, rtype)
f73dda09 812 char *s;
7117c2d2 813 int quoted, *rtype;
f73dda09 814{
7117c2d2 815 return (array_value_internal (s, quoted, 1, rtype));
f73dda09
JA
816}
817
818/* Return the value of the array indexing expression S as a single string.
819 If ALLOW_ALL is 0, do not allow `@' and `*' subscripts. This is used
820 by other parts of the shell such as the arithmetic expression evaluator
821 in expr.c. */
822char *
7117c2d2 823get_array_value (s, allow_all, rtype)
f73dda09 824 char *s;
7117c2d2 825 int allow_all, *rtype;
f73dda09 826{
7117c2d2 827 return (array_value_internal (s, 0, allow_all, rtype));
f73dda09
JA
828}
829
d3a24ed2
CR
830char *
831array_keys (s, quoted)
832 char *s;
833 int quoted;
834{
835 int len;
836 char *retval, *t, *temp;
837 WORD_LIST *l;
838 SHELL_VAR *var;
839
840 var = array_variable_part (s, &t, &len);
841
842 /* [ */
843 if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']')
844 return (char *)NULL;
845
846 if (array_p (var) == 0)
847 l = add_string_to_list ("0", (WORD_LIST *)NULL);
848 else
849 {
850 l = array_keys_to_word_list (array_cell (var));
851 if (l == (WORD_LIST *)NULL)
852 return ((char *) NULL);
853 }
854
855 if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
856 {
857 temp = string_list_dollar_star (l);
858 retval = quote_string (temp);
859 free (temp);
860 }
861 else /* ${!name[@]} or unquoted ${!name[*]} */
862 retval = string_list_dollar_at (l, quoted);
863
864 dispose_words (l);
865 return retval;
866}
f73dda09 867#endif /* ARRAY_VARS */