]> git.ipfire.org Git - thirdparty/bash.git/blob - arrayfunc.c
allow assignment to array keys @ and *; minor completion fix
[thirdparty/bash.git] / arrayfunc.c
1 /* arrayfunc.c -- High-level array functions used by other parts of the shell. */
2
3 /* Copyright (C) 2001-2021 Free Software Foundation, Inc.
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
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.
11
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.
16
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 */
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
30 #include "bashintl.h"
31
32 #include "shell.h"
33 #include "execute_cmd.h"
34 #include "pathexp.h"
35
36 #include "shmbutil.h"
37 #if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
38 # include <mbstr.h> /* mbschr */
39 #endif
40
41 #include "builtins/common.h"
42
43 #ifndef LBRACK
44 # define LBRACK '['
45 # define RBRACK ']'
46 #endif
47
48 /* This variable means to not expand associative array subscripts more than
49 once, when performing variable expansion. */
50 int assoc_expand_once = 0;
51
52 /* Ditto for indexed array subscripts -- currently unused */
53 int array_expand_once = 0;
54
55 static SHELL_VAR *bind_array_var_internal PARAMS((SHELL_VAR *, arrayind_t, char *, char *, int));
56 static SHELL_VAR *assign_array_element_internal PARAMS((SHELL_VAR *, char *, char *, char *, int, char *, int));
57
58 static void assign_assoc_from_kvlist PARAMS((SHELL_VAR *, WORD_LIST *, HASH_TABLE *, int));
59
60 static char *quote_assign PARAMS((const char *));
61 static void quote_array_assignment_chars PARAMS((WORD_LIST *));
62 static char *quote_compound_array_word PARAMS((char *, int));
63 static char *array_value_internal PARAMS((const char *, int, int, int *, arrayind_t *));
64
65 /* Standard error message to use when encountering an invalid array subscript */
66 const char * const bash_badsub_errmsg = N_("bad array subscript");
67
68 /* **************************************************************** */
69 /* */
70 /* Functions to manipulate array variables and perform assignments */
71 /* */
72 /* **************************************************************** */
73
74 /* Convert a shell variable to an array variable. The original value is
75 saved as array[0]. */
76 SHELL_VAR *
77 convert_var_to_array (var)
78 SHELL_VAR *var;
79 {
80 char *oldval;
81 ARRAY *array;
82
83 oldval = value_cell (var);
84 array = array_create ();
85 if (oldval)
86 array_insert (array, 0, oldval);
87
88 FREE (value_cell (var));
89 var_setarray (var, array);
90
91 /* these aren't valid anymore */
92 var->dynamic_value = (sh_var_value_func_t *)NULL;
93 var->assign_func = (sh_var_assign_func_t *)NULL;
94
95 INVALIDATE_EXPORTSTR (var);
96 if (exported_p (var))
97 array_needs_making++;
98
99 VSETATTR (var, att_array);
100 if (oldval)
101 VUNSETATTR (var, att_invisible);
102
103 /* Make sure it's not marked as an associative array any more */
104 VUNSETATTR (var, att_assoc);
105
106 /* Since namerefs can't be array variables, turn off nameref attribute */
107 VUNSETATTR (var, att_nameref);
108
109 return var;
110 }
111
112 /* Convert a shell variable to an array variable. The original value is
113 saved as array[0]. */
114 SHELL_VAR *
115 convert_var_to_assoc (var)
116 SHELL_VAR *var;
117 {
118 char *oldval;
119 HASH_TABLE *hash;
120
121 oldval = value_cell (var);
122 hash = assoc_create (0);
123 if (oldval)
124 assoc_insert (hash, savestring ("0"), oldval);
125
126 FREE (value_cell (var));
127 var_setassoc (var, hash);
128
129 /* these aren't valid anymore */
130 var->dynamic_value = (sh_var_value_func_t *)NULL;
131 var->assign_func = (sh_var_assign_func_t *)NULL;
132
133 INVALIDATE_EXPORTSTR (var);
134 if (exported_p (var))
135 array_needs_making++;
136
137 VSETATTR (var, att_assoc);
138 if (oldval)
139 VUNSETATTR (var, att_invisible);
140
141 /* Make sure it's not marked as an indexed array any more */
142 VUNSETATTR (var, att_array);
143
144 /* Since namerefs can't be array variables, turn off nameref attribute */
145 VUNSETATTR (var, att_nameref);
146
147 return var;
148 }
149
150 char *
151 make_array_variable_value (entry, ind, key, value, flags)
152 SHELL_VAR *entry;
153 arrayind_t ind;
154 char *key;
155 char *value;
156 int flags;
157 {
158 SHELL_VAR *dentry;
159 char *newval;
160
161 /* If we're appending, we need the old value of the array reference, so
162 fake out make_variable_value with a dummy SHELL_VAR */
163 if (flags & ASS_APPEND)
164 {
165 dentry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
166 dentry->name = savestring (entry->name);
167 if (assoc_p (entry))
168 newval = assoc_reference (assoc_cell (entry), key);
169 else
170 newval = array_reference (array_cell (entry), ind);
171 if (newval)
172 dentry->value = savestring (newval);
173 else
174 {
175 dentry->value = (char *)xmalloc (1);
176 dentry->value[0] = '\0';
177 }
178 dentry->exportstr = 0;
179 dentry->attributes = entry->attributes & ~(att_array|att_assoc|att_exported);
180 /* Leave the rest of the members uninitialized; the code doesn't look
181 at them. */
182 newval = make_variable_value (dentry, value, flags);
183 dispose_variable (dentry);
184 }
185 else
186 newval = make_variable_value (entry, value, flags);
187
188 return newval;
189 }
190
191 /* Assign HASH[KEY]=VALUE according to FLAGS. ENTRY is an associative array
192 variable; HASH is the hash table to assign into. HASH may or may not be
193 the hash table associated with ENTRY; if it's not, the caller takes care
194 of it.
195 XXX - make sure that any dynamic associative array variables recreate the
196 hash table on each assignment. BASH_CMDS and BASH_ALIASES already do this */
197 static SHELL_VAR *
198 bind_assoc_var_internal (entry, hash, key, value, flags)
199 SHELL_VAR *entry;
200 HASH_TABLE *hash;
201 char *key;
202 char *value;
203 int flags;
204 {
205 char *newval;
206
207 /* Use the existing array contents to expand the value */
208 newval = make_array_variable_value (entry, 0, key, value, flags);
209
210 if (entry->assign_func)
211 (*entry->assign_func) (entry, newval, 0, key);
212 else
213 assoc_insert (hash, key, newval);
214
215 FREE (newval);
216
217 VUNSETATTR (entry, att_invisible); /* no longer invisible */
218
219 /* check mark_modified_variables if we ever want to export array vars */
220 return (entry);
221 }
222
223 /* Perform ENTRY[IND]=VALUE or ENTRY[KEY]=VALUE. This is not called for every
224 assignment to an associative array; see assign_compound_array_list below. */
225 static SHELL_VAR *
226 bind_array_var_internal (entry, ind, key, value, flags)
227 SHELL_VAR *entry;
228 arrayind_t ind;
229 char *key;
230 char *value;
231 int flags;
232 {
233 char *newval;
234
235 newval = make_array_variable_value (entry, ind, key, value, flags);
236
237 if (entry->assign_func)
238 (*entry->assign_func) (entry, newval, ind, key);
239 else if (assoc_p (entry))
240 assoc_insert (assoc_cell (entry), key, newval);
241 else
242 array_insert (array_cell (entry), ind, newval);
243 FREE (newval);
244
245 VUNSETATTR (entry, att_invisible); /* no longer invisible */
246
247 /* check mark_modified_variables if we ever want to export array vars */
248 return (entry);
249 }
250
251 /* Perform an array assignment name[ind]=value. If NAME already exists and
252 is not an array, and IND is 0, perform name=value instead. If NAME exists
253 and is not an array, and IND is not 0, convert it into an array with the
254 existing value as name[0].
255
256 If NAME does not exist, just create an array variable, no matter what
257 IND's value may be. */
258 SHELL_VAR *
259 bind_array_variable (name, ind, value, flags)
260 char *name;
261 arrayind_t ind;
262 char *value;
263 int flags;
264 {
265 SHELL_VAR *entry;
266
267 entry = find_shell_variable (name);
268
269 if (entry == (SHELL_VAR *) 0)
270 {
271 /* Is NAME a nameref variable that points to an unset variable? */
272 entry = find_variable_nameref_for_create (name, 0);
273 if (entry == INVALID_NAMEREF_VALUE)
274 return ((SHELL_VAR *)0);
275 if (entry && nameref_p (entry))
276 entry = make_new_array_variable (nameref_cell (entry));
277 }
278 if (entry == (SHELL_VAR *) 0)
279 entry = make_new_array_variable (name);
280 else if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry))
281 {
282 if (readonly_p (entry))
283 err_readonly (name);
284 return (entry);
285 }
286 else if (array_p (entry) == 0)
287 entry = convert_var_to_array (entry);
288
289 /* ENTRY is an array variable, and ARRAY points to the value. */
290 return (bind_array_var_internal (entry, ind, 0, value, flags));
291 }
292
293 SHELL_VAR *
294 bind_array_element (entry, ind, value, flags)
295 SHELL_VAR *entry;
296 arrayind_t ind;
297 char *value;
298 int flags;
299 {
300 return (bind_array_var_internal (entry, ind, 0, value, flags));
301 }
302
303 SHELL_VAR *
304 bind_assoc_variable (entry, name, key, value, flags)
305 SHELL_VAR *entry;
306 char *name;
307 char *key;
308 char *value;
309 int flags;
310 {
311 if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry))
312 {
313 if (readonly_p (entry))
314 err_readonly (name);
315 return (entry);
316 }
317
318 return (bind_assoc_var_internal (entry, assoc_cell (entry), key, value, flags));
319 }
320
321 /* Parse NAME, a lhs of an assignment statement of the form v[s], and
322 assign VALUE to that array element by calling bind_array_variable().
323 Flags are ASS_ assignment flags */
324 SHELL_VAR *
325 assign_array_element (name, value, flags)
326 char *name, *value;
327 int flags;
328 {
329 char *sub, *vname;
330 int sublen, isassoc;
331 SHELL_VAR *entry;
332
333 vname = array_variable_name (name, (flags & ASS_NOEXPAND) != 0, &sub, &sublen);
334
335 if (vname == 0)
336 return ((SHELL_VAR *)NULL);
337
338 entry = find_variable (vname);
339 isassoc = entry && assoc_p (entry);
340
341 /* We don't allow assignment to `*' or `@' associative array keys if the
342 caller hasn't told us the subscript has already been expanded
343 (ASS_NOEXPAND). If the caller has explicitly told us it's ok
344 (ASS_ALLOWALLSUB) we allow it. */
345 if (((isassoc == 0 || (flags & (ASS_NOEXPAND|ASS_ALLOWALLSUB)) == 0) &&
346 (ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']')) ||
347 (sublen <= 1))
348 {
349 free (vname);
350 err_badarraysub (name);
351 return ((SHELL_VAR *)NULL);
352 }
353
354 entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags);
355
356 free (vname);
357 return entry;
358 }
359
360 static SHELL_VAR *
361 assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
362 SHELL_VAR *entry;
363 char *name; /* only used for error messages */
364 char *vname;
365 char *sub;
366 int sublen;
367 char *value;
368 int flags;
369 {
370 char *akey;
371 arrayind_t ind;
372
373 if (entry && assoc_p (entry))
374 {
375 sub[sublen-1] = '\0';
376 if ((flags & ASS_NOEXPAND) == 0)
377 akey = expand_assignment_string_to_string (sub, 0); /* [ */
378 else
379 akey = savestring (sub);
380 sub[sublen-1] = ']';
381 if (akey == 0 || *akey == 0)
382 {
383 err_badarraysub (name);
384 FREE (akey);
385 return ((SHELL_VAR *)NULL);
386 }
387 entry = bind_assoc_variable (entry, vname, akey, value, flags);
388 }
389 else
390 {
391 ind = array_expand_index (entry, sub, sublen, 0);
392 /* negative subscripts to indexed arrays count back from end */
393 if (entry && ind < 0)
394 ind = (array_p (entry) ? array_max_index (array_cell (entry)) : 0) + 1 + ind;
395 if (ind < 0)
396 {
397 err_badarraysub (name);
398 return ((SHELL_VAR *)NULL);
399 }
400 entry = bind_array_variable (vname, ind, value, flags);
401 }
402
403 return (entry);
404 }
405
406 /* Find the array variable corresponding to NAME. If there is no variable,
407 create a new array variable. If the variable exists but is not an array,
408 convert it to an indexed array. If FLAGS&1 is non-zero, an existing
409 variable is checked for the readonly or noassign attribute in preparation
410 for assignment (e.g., by the `read' builtin). If FLAGS&2 is non-zero, we
411 create an associative array. */
412 SHELL_VAR *
413 find_or_make_array_variable (name, flags)
414 char *name;
415 int flags;
416 {
417 SHELL_VAR *var;
418
419 var = find_variable (name);
420 if (var == 0)
421 {
422 /* See if we have a nameref pointing to a variable that hasn't been
423 created yet. */
424 var = find_variable_last_nameref (name, 1);
425 if (var && nameref_p (var) && invisible_p (var))
426 {
427 internal_warning (_("%s: removing nameref attribute"), name);
428 VUNSETATTR (var, att_nameref);
429 }
430 if (var && nameref_p (var))
431 {
432 if (valid_nameref_value (nameref_cell (var), 2) == 0)
433 {
434 sh_invalidid (nameref_cell (var));
435 return ((SHELL_VAR *)NULL);
436 }
437 var = (flags & 2) ? make_new_assoc_variable (nameref_cell (var)) : make_new_array_variable (nameref_cell (var));
438 }
439 }
440
441 if (var == 0)
442 var = (flags & 2) ? make_new_assoc_variable (name) : make_new_array_variable (name);
443 else if ((flags & 1) && (readonly_p (var) || noassign_p (var)))
444 {
445 if (readonly_p (var))
446 err_readonly (name);
447 return ((SHELL_VAR *)NULL);
448 }
449 else if ((flags & 2) && array_p (var))
450 {
451 set_exit_status (EXECUTION_FAILURE);
452 report_error (_("%s: cannot convert indexed to associative array"), name);
453 return ((SHELL_VAR *)NULL);
454 }
455 else if (array_p (var) == 0 && assoc_p (var) == 0)
456 var = convert_var_to_array (var);
457
458 return (var);
459 }
460
461 /* Perform a compound assignment statement for array NAME, where VALUE is
462 the text between the parens: NAME=( VALUE ) */
463 SHELL_VAR *
464 assign_array_from_string (name, value, flags)
465 char *name, *value;
466 int flags;
467 {
468 SHELL_VAR *var;
469 int vflags;
470
471 vflags = 1;
472 if (flags & ASS_MKASSOC)
473 vflags |= 2;
474
475 var = find_or_make_array_variable (name, vflags);
476 if (var == 0)
477 return ((SHELL_VAR *)NULL);
478
479 return (assign_array_var_from_string (var, value, flags));
480 }
481
482 /* Sequentially assign the indices of indexed array variable VAR from the
483 words in LIST. */
484 SHELL_VAR *
485 assign_array_var_from_word_list (var, list, flags)
486 SHELL_VAR *var;
487 WORD_LIST *list;
488 int flags;
489 {
490 register arrayind_t i;
491 register WORD_LIST *l;
492 ARRAY *a;
493
494 a = array_cell (var);
495 i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
496
497 for (l = list; l; l = l->next, i++)
498 bind_array_var_internal (var, i, 0, l->word->word, flags & ~ASS_APPEND);
499
500 VUNSETATTR (var, att_invisible); /* no longer invisible */
501
502 return var;
503 }
504
505 WORD_LIST *
506 expand_compound_array_assignment (var, value, flags)
507 SHELL_VAR *var;
508 char *value;
509 int flags;
510 {
511 WORD_LIST *list, *nlist;
512 char *val;
513 int ni;
514
515 /* This condition is true when invoked from the declare builtin with a
516 command like
517 declare -a d='([1]="" [2]="bdef" [5]="hello world" "test")' */
518 if (*value == '(') /*)*/
519 {
520 ni = 1;
521 val = extract_array_assignment_list (value, &ni);
522 if (val == 0)
523 return (WORD_LIST *)NULL;
524 }
525 else
526 val = value;
527
528 /* Expand the value string into a list of words, performing all the
529 shell expansions including pathname generation and word splitting. */
530 /* First we split the string on whitespace, using the shell parser
531 (ksh93 seems to do this). */
532 list = parse_string_to_word_list (val, 1, "array assign");
533
534 /* Note that we defer expansion of the assignment statements for associative
535 arrays here, so we don't have to scan the subscript and find the ending
536 bracket twice. See the caller below. */
537 if (var && assoc_p (var))
538 {
539 if (val != value)
540 free (val);
541 return list;
542 }
543
544 /* If we're using [subscript]=value, we need to quote each [ and ] to
545 prevent unwanted filename expansion. This doesn't need to be done
546 for associative array expansion, since that uses a different expansion
547 function (see assign_compound_array_list below). */
548 if (list)
549 quote_array_assignment_chars (list);
550
551 /* Now that we've split it, perform the shell expansions on each
552 word in the list. */
553 nlist = list ? expand_words_no_vars (list) : (WORD_LIST *)NULL;
554
555 dispose_words (list);
556
557 if (val != value)
558 free (val);
559
560 return nlist;
561 }
562
563 #if ASSOC_KVPAIR_ASSIGNMENT
564 static void
565 assign_assoc_from_kvlist (var, nlist, h, flags)
566 SHELL_VAR *var;
567 WORD_LIST *nlist;
568 HASH_TABLE *h;
569 int flags;
570 {
571 WORD_LIST *list;
572 char *akey, *aval, *k, *v;
573
574 for (list = nlist; list; list = list->next)
575 {
576 k = list->word->word;
577 v = list->next ? list->next->word->word : 0;
578
579 if (list->next)
580 list = list->next;
581
582 akey = expand_assignment_string_to_string (k, 0);
583 if (akey == 0 || *akey == 0)
584 {
585 err_badarraysub (k);
586 FREE (akey);
587 continue;
588 }
589
590 aval = expand_assignment_string_to_string (v, 0);
591 if (aval == 0)
592 {
593 aval = (char *)xmalloc (1);
594 aval[0] = '\0'; /* like do_assignment_internal */
595 }
596
597 bind_assoc_var_internal (var, h, akey, aval, flags);
598 free (aval);
599 }
600 }
601
602 /* Return non-zero if L appears to be a key-value pair associative array
603 compound assignment. */
604 int
605 kvpair_assignment_p (l)
606 WORD_LIST *l;
607 {
608 return (l && (l->word->flags & W_ASSIGNMENT) == 0 && l->word->word[0] != '['); /*]*/
609 }
610
611 char *
612 expand_and_quote_kvpair_word (w)
613 char *w;
614 {
615 char *t, *r;
616
617 t = w ? expand_assignment_string_to_string (w, 0) : 0;
618 r = sh_single_quote (t ? t : "");
619 free (t);
620 return r;
621 }
622 #endif
623
624 /* Callers ensure that VAR is not NULL. Associative array assignments have not
625 been expanded when this is called, or have been expanded once and single-
626 quoted, so we don't have to scan through an unquoted expanded subscript to
627 find the ending bracket; indexed array assignments have been expanded and
628 possibly single-quoted to prevent further expansion.
629
630 If this is an associative array, we perform the assignments into NHASH and
631 set NHASH to be the value of VAR after processing the assignments in NLIST */
632 void
633 assign_compound_array_list (var, nlist, flags)
634 SHELL_VAR *var;
635 WORD_LIST *nlist;
636 int flags;
637 {
638 ARRAY *a;
639 HASH_TABLE *h, *nhash;
640 WORD_LIST *list;
641 char *w, *val, *nval, *savecmd;
642 int len, iflags, free_val;
643 arrayind_t ind, last_ind;
644 char *akey;
645
646 a = (var && array_p (var)) ? array_cell (var) : (ARRAY *)0;
647 nhash = h = (var && assoc_p (var)) ? assoc_cell (var) : (HASH_TABLE *)0;
648
649 akey = (char *)0;
650 ind = 0;
651
652 /* Now that we are ready to assign values to the array, kill the existing
653 value. */
654 if ((flags & ASS_APPEND) == 0)
655 {
656 if (a && array_p (var))
657 array_flush (a);
658 else if (h && assoc_p (var))
659 nhash = assoc_create (h->nbuckets);
660 }
661
662 last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0;
663
664 #if ASSOC_KVPAIR_ASSIGNMENT
665 if (assoc_p (var) && kvpair_assignment_p (nlist))
666 {
667 iflags = flags & ~ASS_APPEND;
668 assign_assoc_from_kvlist (var, nlist, nhash, iflags);
669 if (nhash && nhash != h)
670 {
671 h = assoc_cell (var);
672 var_setassoc (var, nhash);
673 assoc_dispose (h);
674 }
675 return;
676 }
677 #endif
678
679 for (list = nlist; list; list = list->next)
680 {
681 /* Don't allow var+=(values) to make assignments in VALUES append to
682 existing values by default. */
683 iflags = flags & ~ASS_APPEND;
684 w = list->word->word;
685
686 /* We have a word of the form [ind]=value */
687 if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
688 {
689 /* Don't have to handle embedded quotes specially any more, since
690 associative array subscripts have not been expanded yet (see
691 above). */
692 len = skipsubscript (w, 0, 0);
693
694 /* XXX - changes for `+=' */
695 if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
696 {
697 if (assoc_p (var))
698 {
699 err_badarraysub (w);
700 continue;
701 }
702 nval = make_variable_value (var, w, flags);
703 if (var->assign_func)
704 (*var->assign_func) (var, nval, last_ind, 0);
705 else
706 array_insert (a, last_ind, nval);
707 FREE (nval);
708 last_ind++;
709 continue;
710 }
711
712 if (len == 1)
713 {
714 err_badarraysub (w);
715 continue;
716 }
717
718 if (ALL_ELEMENT_SUB (w[1]) && len == 2 && array_p (var))
719 {
720 set_exit_status (EXECUTION_FAILURE);
721 report_error (_("%s: cannot assign to non-numeric index"), w);
722 continue;
723 }
724
725 if (array_p (var))
726 {
727 ind = array_expand_index (var, w + 1, len, 0);
728 /* negative subscripts to indexed arrays count back from end */
729 if (ind < 0)
730 ind = array_max_index (array_cell (var)) + 1 + ind;
731 if (ind < 0)
732 {
733 err_badarraysub (w);
734 continue;
735 }
736
737 last_ind = ind;
738 }
739 else if (assoc_p (var))
740 {
741 /* This is not performed above, see expand_compound_array_assignment */
742 w[len] = '\0'; /*[*/
743 akey = expand_assignment_string_to_string (w+1, 0);
744 w[len] = ']';
745 /* And we need to expand the value also, see below */
746 if (akey == 0 || *akey == 0)
747 {
748 err_badarraysub (w);
749 FREE (akey);
750 continue;
751 }
752 }
753
754 /* XXX - changes for `+=' -- just accept the syntax. ksh93 doesn't do this */
755 if (w[len + 1] == '+' && w[len + 2] == '=')
756 {
757 iflags |= ASS_APPEND;
758 val = w + len + 3;
759 }
760 else
761 val = w + len + 2;
762 }
763 else if (assoc_p (var))
764 {
765 set_exit_status (EXECUTION_FAILURE);
766 report_error (_("%s: %s: must use subscript when assigning associative array"), var->name, w);
767 continue;
768 }
769 else /* No [ind]=value, just a stray `=' */
770 {
771 ind = last_ind;
772 val = w;
773 }
774
775 free_val = 0;
776 /* See above; we need to expand the value here */
777 if (assoc_p (var))
778 {
779 val = expand_assignment_string_to_string (val, 0);
780 if (val == 0)
781 {
782 val = (char *)xmalloc (1);
783 val[0] = '\0'; /* like do_assignment_internal */
784 }
785 free_val = 1;
786 }
787
788 savecmd = this_command_name;
789 if (integer_p (var))
790 this_command_name = (char *)NULL; /* no command name for errors */
791 if (assoc_p (var))
792 bind_assoc_var_internal (var, nhash, akey, val, iflags);
793 else
794 bind_array_var_internal (var, ind, akey, val, iflags);
795 last_ind++;
796 this_command_name = savecmd;
797
798 if (free_val)
799 free (val);
800 }
801
802 if (assoc_p (var) && nhash && nhash != h)
803 {
804 h = assoc_cell (var);
805 var_setassoc (var, nhash);
806 assoc_dispose (h);
807 }
808 }
809
810 /* Perform a compound array assignment: VAR->name=( VALUE ). The
811 VALUE has already had the parentheses stripped. */
812 SHELL_VAR *
813 assign_array_var_from_string (var, value, flags)
814 SHELL_VAR *var;
815 char *value;
816 int flags;
817 {
818 WORD_LIST *nlist;
819
820 if (value == 0)
821 return var;
822
823 nlist = expand_compound_array_assignment (var, value, flags);
824 assign_compound_array_list (var, nlist, flags);
825
826 if (nlist)
827 dispose_words (nlist);
828
829 if (var)
830 VUNSETATTR (var, att_invisible); /* no longer invisible */
831
832 return (var);
833 }
834
835 /* Quote globbing chars and characters in $IFS before the `=' in an assignment
836 statement (usually a compound array assignment) to protect them from
837 unwanted filename expansion or word splitting. */
838 static char *
839 quote_assign (string)
840 const char *string;
841 {
842 size_t slen;
843 int saw_eq;
844 char *temp, *t, *subs;
845 const char *s, *send;
846 int ss, se;
847 DECLARE_MBSTATE;
848
849 slen = strlen (string);
850 send = string + slen;
851
852 t = temp = (char *)xmalloc (slen * 2 + 1);
853 saw_eq = 0;
854 for (s = string; *s; )
855 {
856 if (*s == '=')
857 saw_eq = 1;
858 if (saw_eq == 0 && *s == '[') /* looks like a subscript */
859 {
860 ss = s - string;
861 se = skipsubscript (string, ss, 0);
862 subs = substring (s, ss, se);
863 *t++ = '\\';
864 strcpy (t, subs);
865 t += se - ss;
866 *t++ = '\\';
867 *t++ = ']';
868 s += se + 1;
869 free (subs);
870 continue;
871 }
872 if (saw_eq == 0 && (glob_char_p (s) || isifs (*s)))
873 *t++ = '\\';
874
875 COPY_CHAR_P (t, s, send);
876 }
877 *t = '\0';
878 return temp;
879 }
880
881 /* Take a word W of the form [IND]=VALUE and transform it to ['IND']='VALUE'
882 to prevent further expansion. This is called for compound assignments to
883 indexed arrays. W has already undergone word expansions. If W has no [IND]=,
884 just single-quote and return it. */
885 static char *
886 quote_compound_array_word (w, type)
887 char *w;
888 int type;
889 {
890 char *nword, *sub, *value, *t;
891 int ind, wlen, i;
892
893 if (w[0] != LBRACK)
894 return (sh_single_quote (w));
895 ind = skipsubscript (w, 0, 0);
896 if (w[ind] != RBRACK)
897 return (sh_single_quote (w));
898
899 wlen = strlen (w);
900 w[ind] = '\0';
901 sub = sh_single_quote (w+1);
902 w[ind] = RBRACK;
903
904 nword = xmalloc (wlen * 4 + 5); /* wlen*4 is max single quoted length */
905 nword[0] = LBRACK;
906 i = STRLEN (sub);
907 memcpy (nword+1, sub, i);
908 i++; /* accommodate the opening LBRACK */
909 nword[i++] = w[ind++]; /* RBRACK */
910 if (w[ind] == '+')
911 nword[i++] = w[ind++];
912 nword[i++] = w[ind++];
913 value = sh_single_quote (w + ind);
914 strcpy (nword + i, value);
915
916 return nword;
917 }
918
919 /* Expand the key and value in W, which is of the form [KEY]=VALUE, and
920 reconstruct W with the expanded and single-quoted version:
921 ['expanded-key']='expanded-value'. If there is no [KEY]=, single-quote the
922 word and return it. Very similar to previous function, but does not assume
923 W has already been expanded, and expands the KEY and VALUE separately.
924 Used for compound assignments to associative arrays that are arguments to
925 declaration builtins (declare -A a=( list )). */
926 char *
927 expand_and_quote_assoc_word (w, type)
928 char *w;
929 int type;
930 {
931 char *nword, *key, *value, *t;
932 int ind, wlen, i;
933
934 if (w[0] != LBRACK)
935 return (sh_single_quote (w));
936 ind = skipsubscript (w, 0, 0);
937 if (w[ind] != RBRACK)
938 return (sh_single_quote (w));
939
940 w[ind] = '\0';
941 t = expand_assignment_string_to_string (w+1, 0);
942 w[ind] = RBRACK;
943 key = sh_single_quote (t ? t : "");
944 free (t);
945
946 wlen = STRLEN (key);
947 nword = xmalloc (wlen + 5);
948 nword[0] = LBRACK;
949 memcpy (nword+1, key, wlen);
950 i = wlen + 1; /* accommodate the opening LBRACK */
951
952 nword[i++] = w[ind++]; /* RBRACK */
953 if (w[ind] == '+')
954 nword[i++] = w[ind++];
955 nword[i++] = w[ind++];
956
957 t = expand_assignment_string_to_string (w+ind, 0);
958 value = sh_single_quote (t ? t : "");
959 free (t);
960 nword = xrealloc (nword, wlen + 5 + STRLEN (value));
961 strcpy (nword + i, value);
962
963 free (key);
964 free (value);
965
966 return nword;
967 }
968
969 /* For each word in a compound array assignment, if the word looks like
970 [ind]=value, single-quote ind and value, but leave the brackets and
971 the = sign (and any `+') alone. If it's not an assignment, just single-
972 quote the word. This is used for indexed arrays. */
973 void
974 quote_compound_array_list (list, type)
975 WORD_LIST *list;
976 int type;
977 {
978 char *t;
979 WORD_LIST *l;
980
981 for (l = list; l; l = l->next)
982 {
983 if (l->word == 0 || l->word->word == 0)
984 continue; /* should not happen, but just in case... */
985 if ((l->word->flags & W_ASSIGNMENT) == 0)
986 t = sh_single_quote (l->word->word);
987 else
988 t = quote_compound_array_word (l->word->word, type);
989 free (l->word->word);
990 l->word->word = t;
991 }
992 }
993
994 /* For each word in a compound array assignment, if the word looks like
995 [ind]=value, quote globbing chars and characters in $IFS before the `='. */
996 static void
997 quote_array_assignment_chars (list)
998 WORD_LIST *list;
999 {
1000 char *nword;
1001 WORD_LIST *l;
1002
1003 for (l = list; l; l = l->next)
1004 {
1005 if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
1006 continue; /* should not happen, but just in case... */
1007 /* Don't bother if it hasn't been recognized as an assignment or
1008 doesn't look like [ind]=value */
1009 if ((l->word->flags & W_ASSIGNMENT) == 0)
1010 continue;
1011 if (l->word->word[0] != '[' || mbschr (l->word->word, '=') == 0) /* ] */
1012 continue;
1013
1014 nword = quote_assign (l->word->word);
1015 free (l->word->word);
1016 l->word->word = nword;
1017 l->word->flags |= W_NOGLOB; /* XXX - W_NOSPLIT also? */
1018 }
1019 }
1020
1021 /* skipsubscript moved to subst.c to use private functions. 2009/02/24. */
1022
1023 /* This function is called with SUB pointing to just after the beginning
1024 `[' of an array subscript and removes the array element to which SUB
1025 expands from array VAR. A subscript of `*' or `@' unsets the array. */
1026 /* If FLAGS&1 (VA_NOEXPAND) we don't expand the subscript; we just use it
1027 as-is. If FLAGS&VA_ONEWORD, we don't try to use skipsubscript to parse
1028 the subscript, we just assume the subscript ends with a close bracket
1029 and use the rest. */
1030 int
1031 unbind_array_element (var, sub, flags)
1032 SHELL_VAR *var;
1033 char *sub;
1034 int flags;
1035 {
1036 int len;
1037 arrayind_t ind;
1038 char *akey;
1039 ARRAY_ELEMENT *ae;
1040
1041 /* If the caller tells us to treat the entire `sub' as one word, we don't
1042 bother to call skipsubscript. */
1043 if (var && assoc_p (var) && (flags&VA_ONEWORD))
1044 len = strlen (sub) - 1;
1045 else
1046 len = skipsubscript (sub, 0, (flags&VA_NOEXPAND) || (var && assoc_p(var))); /* XXX */
1047 if (sub[len] != ']' || len == 0)
1048 {
1049 builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg));
1050 return -1;
1051 }
1052 sub[len] = '\0';
1053
1054 if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0)
1055 {
1056 if (array_p (var) || assoc_p (var))
1057 {
1058 #if 0 /* TAG: bash-5.2 */
1059 if (flags & VA_ALLOWALL)
1060 #endif
1061 {
1062 unbind_variable (var->name); /* XXX -- {array,assoc}_flush ? */
1063 return (0);
1064 }
1065 /* otherwise we fall through and try to unset element `@' or `*' */
1066 }
1067 else
1068 return -2; /* don't allow this to unset scalar variables */
1069 }
1070
1071 if (assoc_p (var))
1072 {
1073 akey = (flags & VA_NOEXPAND) ? sub : expand_assignment_string_to_string (sub, 0);
1074 if (akey == 0 || *akey == 0)
1075 {
1076 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
1077 FREE (akey);
1078 return -1;
1079 }
1080 assoc_remove (assoc_cell (var), akey);
1081 if (akey != sub)
1082 free (akey);
1083 }
1084 else if (array_p (var))
1085 {
1086 ind = array_expand_index (var, sub, len+1, 0);
1087 /* negative subscripts to indexed arrays count back from end */
1088 if (ind < 0)
1089 ind = array_max_index (array_cell (var)) + 1 + ind;
1090 if (ind < 0)
1091 {
1092 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
1093 return -1;
1094 }
1095 ae = array_remove (array_cell (var), ind);
1096 if (ae)
1097 array_dispose_element (ae);
1098 }
1099 else /* array_p (var) == 0 && assoc_p (var) == 0 */
1100 {
1101 akey = this_command_name;
1102 ind = array_expand_index (var, sub, len+1, 0);
1103 this_command_name = akey;
1104 if (ind == 0)
1105 {
1106 unbind_variable (var->name);
1107 return (0);
1108 }
1109 else
1110 return -2; /* any subscript other than 0 is invalid with scalar variables */
1111 }
1112
1113 return 0;
1114 }
1115
1116 /* Format and output an array assignment in compound form VAR=(VALUES),
1117 suitable for re-use as input. */
1118 void
1119 print_array_assignment (var, quoted)
1120 SHELL_VAR *var;
1121 int quoted;
1122 {
1123 char *vstr;
1124
1125 vstr = array_to_assign (array_cell (var), quoted);
1126
1127 if (vstr == 0)
1128 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
1129 else
1130 {
1131 printf ("%s=%s\n", var->name, vstr);
1132 free (vstr);
1133 }
1134 }
1135
1136 /* Format and output an associative array assignment in compound form
1137 VAR=(VALUES), suitable for re-use as input. */
1138 void
1139 print_assoc_assignment (var, quoted)
1140 SHELL_VAR *var;
1141 int quoted;
1142 {
1143 char *vstr;
1144
1145 vstr = assoc_to_assign (assoc_cell (var), quoted);
1146
1147 if (vstr == 0)
1148 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
1149 else
1150 {
1151 printf ("%s=%s\n", var->name, vstr);
1152 free (vstr);
1153 }
1154 }
1155
1156 /***********************************************************************/
1157 /* */
1158 /* Utility functions to manage arrays and their contents for expansion */
1159 /* */
1160 /***********************************************************************/
1161
1162 /* Return 1 if NAME is a properly-formed array reference v[sub]. */
1163
1164 /* We need to reserve 1 for FLAGS, which we pass to skipsubscript. */
1165 int
1166 valid_array_reference (name, flags)
1167 const char *name;
1168 int flags;
1169 {
1170 char *t;
1171 int r, len, isassoc;
1172 SHELL_VAR *entry;
1173
1174 t = mbschr (name, '['); /* ] */
1175 isassoc = 0;
1176 if (t)
1177 {
1178 *t = '\0';
1179 r = legal_identifier (name);
1180 if (flags & VA_NOEXPAND) /* Don't waste a lookup if we don't need one */
1181 isassoc = (entry = find_variable (name)) && assoc_p (entry);
1182 *t = '[';
1183 if (r == 0)
1184 return 0;
1185
1186 if (isassoc && ((flags & (VA_NOEXPAND|VA_ONEWORD)) == (VA_NOEXPAND|VA_ONEWORD)))
1187 len = strlen (t) - 1;
1188 else if (isassoc)
1189 len = skipsubscript (t, 0, flags&VA_NOEXPAND); /* VA_NOEXPAND must be 1 */
1190 else
1191 /* Check for a properly-terminated non-null subscript. */
1192 len = skipsubscript (t, 0, 0); /* arithmetic expression */
1193
1194 if (t[len] != ']' || len == 1 || t[len+1] != '\0')
1195 return 0;
1196
1197 #if 0
1198 /* Could check and allow subscripts consisting only of whitespace for
1199 existing associative arrays, using isassoc */
1200 for (r = 1; r < len; r++)
1201 if (whitespace (t[r]) == 0)
1202 return 1;
1203 return 0;
1204 #else
1205 /* This allows blank subscripts */
1206 return 1;
1207 #endif
1208 }
1209 return 0;
1210 }
1211
1212 /* Expand the array index beginning at S and extending LEN characters. */
1213 arrayind_t
1214 array_expand_index (var, s, len, flags)
1215 SHELL_VAR *var;
1216 char *s;
1217 int len;
1218 int flags;
1219 {
1220 char *exp, *t, *savecmd;
1221 int expok;
1222 arrayind_t val;
1223
1224 exp = (char *)xmalloc (len);
1225 strncpy (exp, s, len - 1);
1226 exp[len - 1] = '\0';
1227 #if 0 /* TAG: maybe bash-5.2 */
1228 if ((flags & AV_NOEXPAND) == 0)
1229 t = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH|Q_ARRAYSUB); /* XXX - Q_ARRAYSUB for future use */
1230 else
1231 t = exp;
1232 #else
1233 t = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH|Q_ARRAYSUB); /* XXX - Q_ARRAYSUB for future use */
1234 #endif
1235 savecmd = this_command_name;
1236 this_command_name = (char *)NULL;
1237 val = evalexp (t, EXP_EXPANDED, &expok); /* XXX - was 0 but we expanded exp already */
1238 this_command_name = savecmd;
1239 if (t != exp)
1240 free (t);
1241 free (exp);
1242 if (expok == 0)
1243 {
1244 set_exit_status (EXECUTION_FAILURE);
1245
1246 if (no_longjmp_on_fatal_error)
1247 return 0;
1248 top_level_cleanup ();
1249 jump_to_top_level (DISCARD);
1250 }
1251 return val;
1252 }
1253
1254 /* Return the name of the variable specified by S without any subscript.
1255 If SUBP is non-null, return a pointer to the start of the subscript
1256 in *SUBP. If LENP is non-null, the length of the subscript is returned
1257 in *LENP. This returns newly-allocated memory. */
1258 char *
1259 array_variable_name (s, flags, subp, lenp)
1260 const char *s;
1261 int flags;
1262 char **subp;
1263 int *lenp;
1264 {
1265 char *t, *ret;
1266 int ind, ni;
1267
1268 t = mbschr (s, '[');
1269 if (t == 0)
1270 {
1271 if (subp)
1272 *subp = t;
1273 if (lenp)
1274 *lenp = 0;
1275 return ((char *)NULL);
1276 }
1277 ind = t - s;
1278 ni = skipsubscript (s, ind, flags); /* XXX - was 0 not flags */
1279 if (ni <= ind + 1 || s[ni] != ']')
1280 {
1281 err_badarraysub (s);
1282 if (subp)
1283 *subp = t;
1284 if (lenp)
1285 *lenp = 0;
1286 return ((char *)NULL);
1287 }
1288
1289 *t = '\0';
1290 ret = savestring (s);
1291 *t++ = '['; /* ] */
1292
1293 if (subp)
1294 *subp = t;
1295 if (lenp)
1296 *lenp = ni - ind;
1297
1298 return ret;
1299 }
1300
1301 /* Return the variable specified by S without any subscript. If SUBP is
1302 non-null, return a pointer to the start of the subscript in *SUBP.
1303 If LENP is non-null, the length of the subscript is returned in *LENP. */
1304 SHELL_VAR *
1305 array_variable_part (s, flags, subp, lenp)
1306 const char *s;
1307 int flags;
1308 char **subp;
1309 int *lenp;
1310 {
1311 char *t;
1312 SHELL_VAR *var;
1313
1314 t = array_variable_name (s, flags, subp, lenp);
1315 if (t == 0)
1316 return ((SHELL_VAR *)NULL);
1317 var = find_variable (t); /* XXX - handle namerefs here? */
1318
1319 free (t);
1320 return var; /* now return invisible variables; caller must handle */
1321 }
1322
1323 #define INDEX_ERROR() \
1324 do \
1325 { \
1326 if (var) \
1327 err_badarraysub (var->name); \
1328 else \
1329 { \
1330 t[-1] = '\0'; \
1331 err_badarraysub (s); \
1332 t[-1] = '['; /* ] */\
1333 } \
1334 return ((char *)NULL); \
1335 } \
1336 while (0)
1337
1338 /* Return a string containing the elements in the array and subscript
1339 described by S. If the subscript is * or @, obeys quoting rules akin
1340 to the expansion of $* and $@ including double quoting. If RTYPE
1341 is non-null it gets 1 if the array reference is name[*], 2 if the
1342 reference is name[@], and 0 otherwise. */
1343 static char *
1344 array_value_internal (s, quoted, flags, rtype, indp)
1345 const char *s;
1346 int quoted, flags, *rtype;
1347 arrayind_t *indp;
1348 {
1349 int len;
1350 arrayind_t ind;
1351 char *akey;
1352 char *retval, *t, *temp;
1353 WORD_LIST *l;
1354 SHELL_VAR *var;
1355
1356 var = array_variable_part (s, (flags&AV_NOEXPAND) ? 1 : 0, &t, &len); /* XXX */
1357
1358 /* Expand the index, even if the variable doesn't exist, in case side
1359 effects are needed, like ${w[i++]} where w is unset. */
1360 #if 0
1361 if (var == 0)
1362 return (char *)NULL;
1363 #endif
1364
1365 if (len == 0)
1366 return ((char *)NULL); /* error message already printed */
1367
1368 /* [ */
1369 akey = 0;
1370 if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
1371 {
1372 if (rtype)
1373 *rtype = (t[0] == '*') ? 1 : 2;
1374 if ((flags & AV_ALLOWALL) == 0)
1375 {
1376 err_badarraysub (s);
1377 return ((char *)NULL);
1378 }
1379 else if (var == 0 || value_cell (var) == 0) /* XXX - check for invisible_p(var) ? */
1380 return ((char *)NULL);
1381 else if (invisible_p (var))
1382 return ((char *)NULL);
1383 else if (array_p (var) == 0 && assoc_p (var) == 0)
1384 l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
1385 else if (assoc_p (var))
1386 {
1387 l = assoc_to_word_list (assoc_cell (var));
1388 if (l == (WORD_LIST *)NULL)
1389 return ((char *)NULL);
1390 }
1391 else
1392 {
1393 l = array_to_word_list (array_cell (var));
1394 if (l == (WORD_LIST *)NULL)
1395 return ((char *) NULL);
1396 }
1397
1398 /* Caller of array_value takes care of inspecting rtype and duplicating
1399 retval if rtype == 0, so this is not a memory leak */
1400 if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
1401 {
1402 temp = string_list_dollar_star (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0);
1403 retval = quote_string (temp);
1404 free (temp);
1405 }
1406 else /* ${name[@]} or unquoted ${name[*]} */
1407 retval = string_list_dollar_at (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0);
1408
1409 dispose_words (l);
1410 }
1411 else
1412 {
1413 if (rtype)
1414 *rtype = 0;
1415 if (var == 0 || array_p (var) || assoc_p (var) == 0)
1416 {
1417 if ((flags & AV_USEIND) == 0 || indp == 0)
1418 {
1419 ind = array_expand_index (var, t, len, flags);
1420 if (ind < 0)
1421 {
1422 /* negative subscripts to indexed arrays count back from end */
1423 if (var && array_p (var))
1424 ind = array_max_index (array_cell (var)) + 1 + ind;
1425 if (ind < 0)
1426 INDEX_ERROR();
1427 }
1428 if (indp)
1429 *indp = ind;
1430 }
1431 else if (indp)
1432 ind = *indp;
1433 }
1434 else if (assoc_p (var))
1435 {
1436 t[len - 1] = '\0';
1437 if ((flags & AV_NOEXPAND) == 0)
1438 akey = expand_assignment_string_to_string (t, 0); /* [ */
1439 else
1440 akey = savestring (t);
1441 t[len - 1] = ']';
1442 if (akey == 0 || *akey == 0)
1443 {
1444 FREE (akey);
1445 INDEX_ERROR();
1446 }
1447 }
1448
1449 if (var == 0 || value_cell (var) == 0) /* XXX - check invisible_p(var) ? */
1450 {
1451 FREE (akey);
1452 return ((char *)NULL);
1453 }
1454 else if (invisible_p (var))
1455 {
1456 FREE (akey);
1457 return ((char *)NULL);
1458 }
1459 if (array_p (var) == 0 && assoc_p (var) == 0)
1460 return (ind == 0 ? value_cell (var) : (char *)NULL);
1461 else if (assoc_p (var))
1462 {
1463 retval = assoc_reference (assoc_cell (var), akey);
1464 free (akey);
1465 }
1466 else
1467 retval = array_reference (array_cell (var), ind);
1468 }
1469
1470 return retval;
1471 }
1472
1473 /* Return a string containing the elements described by the array and
1474 subscript contained in S, obeying quoting for subscripts * and @. */
1475 char *
1476 array_value (s, quoted, flags, rtype, indp)
1477 const char *s;
1478 int quoted, flags, *rtype;
1479 arrayind_t *indp;
1480 {
1481 return (array_value_internal (s, quoted, flags|AV_ALLOWALL, rtype, indp));
1482 }
1483
1484 /* Return the value of the array indexing expression S as a single string.
1485 If (FLAGS & AV_ALLOWALL) is 0, do not allow `@' and `*' subscripts. This
1486 is used by other parts of the shell such as the arithmetic expression
1487 evaluator in expr.c. */
1488 char *
1489 get_array_value (s, flags, rtype, indp)
1490 const char *s;
1491 int flags, *rtype;
1492 arrayind_t *indp;
1493 {
1494 return (array_value_internal (s, 0, flags, rtype, indp));
1495 }
1496
1497 char *
1498 array_keys (s, quoted, pflags)
1499 char *s;
1500 int quoted, pflags;
1501 {
1502 int len;
1503 char *retval, *t, *temp;
1504 WORD_LIST *l;
1505 SHELL_VAR *var;
1506
1507 var = array_variable_part (s, 0, &t, &len);
1508
1509 /* [ */
1510 if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']')
1511 return (char *)NULL;
1512
1513 if (var_isset (var) == 0 || invisible_p (var))
1514 return (char *)NULL;
1515
1516 if (array_p (var) == 0 && assoc_p (var) == 0)
1517 l = add_string_to_list ("0", (WORD_LIST *)NULL);
1518 else if (assoc_p (var))
1519 l = assoc_keys_to_word_list (assoc_cell (var));
1520 else
1521 l = array_keys_to_word_list (array_cell (var));
1522 if (l == (WORD_LIST *)NULL)
1523 return ((char *) NULL);
1524
1525 retval = string_list_pos_params (t[0], l, quoted, pflags);
1526
1527 dispose_words (l);
1528 return retval;
1529 }
1530 #endif /* ARRAY_VARS */