]> git.ipfire.org Git - thirdparty/bash.git/blob - arrayfunc.c
Bash-5.1 patch 5: fix memory leaks in compound array assignments
[thirdparty/bash.git] / arrayfunc.c
1 /* arrayfunc.c -- High-level array functions used by other parts of the shell. */
2
3 /* Copyright (C) 2001-2020 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 if (((isassoc == 0 || (flags & ASS_NOEXPAND) == 0) && (ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']')) || (sublen <= 1))
342 {
343 free (vname);
344 err_badarraysub (name);
345 return ((SHELL_VAR *)NULL);
346 }
347
348 entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags);
349
350 free (vname);
351 return entry;
352 }
353
354 static SHELL_VAR *
355 assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
356 SHELL_VAR *entry;
357 char *name; /* only used for error messages */
358 char *vname;
359 char *sub;
360 int sublen;
361 char *value;
362 int flags;
363 {
364 char *akey;
365 arrayind_t ind;
366
367 if (entry && assoc_p (entry))
368 {
369 sub[sublen-1] = '\0';
370 if ((flags & ASS_NOEXPAND) == 0)
371 akey = expand_assignment_string_to_string (sub, 0); /* [ */
372 else
373 akey = savestring (sub);
374 sub[sublen-1] = ']';
375 if (akey == 0 || *akey == 0)
376 {
377 err_badarraysub (name);
378 FREE (akey);
379 return ((SHELL_VAR *)NULL);
380 }
381 entry = bind_assoc_variable (entry, vname, akey, value, flags);
382 }
383 else
384 {
385 ind = array_expand_index (entry, sub, sublen, 0);
386 /* negative subscripts to indexed arrays count back from end */
387 if (entry && ind < 0)
388 ind = (array_p (entry) ? array_max_index (array_cell (entry)) : 0) + 1 + ind;
389 if (ind < 0)
390 {
391 err_badarraysub (name);
392 return ((SHELL_VAR *)NULL);
393 }
394 entry = bind_array_variable (vname, ind, value, flags);
395 }
396
397 return (entry);
398 }
399
400 /* Find the array variable corresponding to NAME. If there is no variable,
401 create a new array variable. If the variable exists but is not an array,
402 convert it to an indexed array. If FLAGS&1 is non-zero, an existing
403 variable is checked for the readonly or noassign attribute in preparation
404 for assignment (e.g., by the `read' builtin). If FLAGS&2 is non-zero, we
405 create an associative array. */
406 SHELL_VAR *
407 find_or_make_array_variable (name, flags)
408 char *name;
409 int flags;
410 {
411 SHELL_VAR *var;
412
413 var = find_variable (name);
414 if (var == 0)
415 {
416 /* See if we have a nameref pointing to a variable that hasn't been
417 created yet. */
418 var = find_variable_last_nameref (name, 1);
419 if (var && nameref_p (var) && invisible_p (var))
420 {
421 internal_warning (_("%s: removing nameref attribute"), name);
422 VUNSETATTR (var, att_nameref);
423 }
424 if (var && nameref_p (var))
425 {
426 if (valid_nameref_value (nameref_cell (var), 2) == 0)
427 {
428 sh_invalidid (nameref_cell (var));
429 return ((SHELL_VAR *)NULL);
430 }
431 var = (flags & 2) ? make_new_assoc_variable (nameref_cell (var)) : make_new_array_variable (nameref_cell (var));
432 }
433 }
434
435 if (var == 0)
436 var = (flags & 2) ? make_new_assoc_variable (name) : make_new_array_variable (name);
437 else if ((flags & 1) && (readonly_p (var) || noassign_p (var)))
438 {
439 if (readonly_p (var))
440 err_readonly (name);
441 return ((SHELL_VAR *)NULL);
442 }
443 else if ((flags & 2) && array_p (var))
444 {
445 set_exit_status (EXECUTION_FAILURE);
446 report_error (_("%s: cannot convert indexed to associative array"), name);
447 return ((SHELL_VAR *)NULL);
448 }
449 else if (array_p (var) == 0 && assoc_p (var) == 0)
450 var = convert_var_to_array (var);
451
452 return (var);
453 }
454
455 /* Perform a compound assignment statement for array NAME, where VALUE is
456 the text between the parens: NAME=( VALUE ) */
457 SHELL_VAR *
458 assign_array_from_string (name, value, flags)
459 char *name, *value;
460 int flags;
461 {
462 SHELL_VAR *var;
463 int vflags;
464
465 vflags = 1;
466 if (flags & ASS_MKASSOC)
467 vflags |= 2;
468
469 var = find_or_make_array_variable (name, vflags);
470 if (var == 0)
471 return ((SHELL_VAR *)NULL);
472
473 return (assign_array_var_from_string (var, value, flags));
474 }
475
476 /* Sequentially assign the indices of indexed array variable VAR from the
477 words in LIST. */
478 SHELL_VAR *
479 assign_array_var_from_word_list (var, list, flags)
480 SHELL_VAR *var;
481 WORD_LIST *list;
482 int flags;
483 {
484 register arrayind_t i;
485 register WORD_LIST *l;
486 ARRAY *a;
487
488 a = array_cell (var);
489 i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
490
491 for (l = list; l; l = l->next, i++)
492 bind_array_var_internal (var, i, 0, l->word->word, flags & ~ASS_APPEND);
493
494 VUNSETATTR (var, att_invisible); /* no longer invisible */
495
496 return var;
497 }
498
499 WORD_LIST *
500 expand_compound_array_assignment (var, value, flags)
501 SHELL_VAR *var;
502 char *value;
503 int flags;
504 {
505 WORD_LIST *list, *nlist;
506 char *val;
507 int ni;
508
509 /* This condition is true when invoked from the declare builtin with a
510 command like
511 declare -a d='([1]="" [2]="bdef" [5]="hello world" "test")' */
512 if (*value == '(') /*)*/
513 {
514 ni = 1;
515 val = extract_array_assignment_list (value, &ni);
516 if (val == 0)
517 return (WORD_LIST *)NULL;
518 }
519 else
520 val = value;
521
522 /* Expand the value string into a list of words, performing all the
523 shell expansions including pathname generation and word splitting. */
524 /* First we split the string on whitespace, using the shell parser
525 (ksh93 seems to do this). */
526 list = parse_string_to_word_list (val, 1, "array assign");
527
528 /* Note that we defer expansion of the assignment statements for associative
529 arrays here, so we don't have to scan the subscript and find the ending
530 bracket twice. See the caller below. */
531 if (var && assoc_p (var))
532 {
533 if (val != value)
534 free (val);
535 return list;
536 }
537
538 /* If we're using [subscript]=value, we need to quote each [ and ] to
539 prevent unwanted filename expansion. This doesn't need to be done
540 for associative array expansion, since that uses a different expansion
541 function (see assign_compound_array_list below). */
542 if (list)
543 quote_array_assignment_chars (list);
544
545 /* Now that we've split it, perform the shell expansions on each
546 word in the list. */
547 nlist = list ? expand_words_no_vars (list) : (WORD_LIST *)NULL;
548
549 dispose_words (list);
550
551 if (val != value)
552 free (val);
553
554 return nlist;
555 }
556
557 #if ASSOC_KVPAIR_ASSIGNMENT
558 static void
559 assign_assoc_from_kvlist (var, nlist, h, flags)
560 SHELL_VAR *var;
561 WORD_LIST *nlist;
562 HASH_TABLE *h;
563 int flags;
564 {
565 WORD_LIST *list;
566 char *akey, *aval, *k, *v;
567
568 for (list = nlist; list; list = list->next)
569 {
570 k = list->word->word;
571 v = list->next ? list->next->word->word : 0;
572
573 if (list->next)
574 list = list->next;
575
576 akey = expand_assignment_string_to_string (k, 0);
577 if (akey == 0 || *akey == 0)
578 {
579 err_badarraysub (k);
580 FREE (akey);
581 continue;
582 }
583
584 aval = expand_assignment_string_to_string (v, 0);
585 if (aval == 0)
586 {
587 aval = (char *)xmalloc (1);
588 aval[0] = '\0'; /* like do_assignment_internal */
589 }
590
591 bind_assoc_var_internal (var, h, akey, aval, flags);
592 free (aval);
593 }
594 }
595
596 /* Return non-zero if L appears to be a key-value pair associative array
597 compound assignment. */
598 int
599 kvpair_assignment_p (l)
600 WORD_LIST *l;
601 {
602 return (l && (l->word->flags & W_ASSIGNMENT) == 0 && l->word->word[0] != '['); /*]*/
603 }
604
605 char *
606 expand_and_quote_kvpair_word (w)
607 char *w;
608 {
609 char *t, *r;
610
611 t = w ? expand_assignment_string_to_string (w, 0) : 0;
612 r = sh_single_quote (t ? t : "");
613 free (t);
614 return r;
615 }
616 #endif
617
618 /* Callers ensure that VAR is not NULL. Associative array assignments have not
619 been expanded when this is called, or have been expanded once and single-
620 quoted, so we don't have to scan through an unquoted expanded subscript to
621 find the ending bracket; indexed array assignments have been expanded and
622 possibly single-quoted to prevent further expansion.
623
624 If this is an associative array, we perform the assignments into NHASH and
625 set NHASH to be the value of VAR after processing the assignments in NLIST */
626 void
627 assign_compound_array_list (var, nlist, flags)
628 SHELL_VAR *var;
629 WORD_LIST *nlist;
630 int flags;
631 {
632 ARRAY *a;
633 HASH_TABLE *h, *nhash;
634 WORD_LIST *list;
635 char *w, *val, *nval, *savecmd;
636 int len, iflags, free_val;
637 arrayind_t ind, last_ind;
638 char *akey;
639
640 a = (var && array_p (var)) ? array_cell (var) : (ARRAY *)0;
641 nhash = h = (var && assoc_p (var)) ? assoc_cell (var) : (HASH_TABLE *)0;
642
643 akey = (char *)0;
644 ind = 0;
645
646 /* Now that we are ready to assign values to the array, kill the existing
647 value. */
648 if ((flags & ASS_APPEND) == 0)
649 {
650 if (a && array_p (var))
651 array_flush (a);
652 else if (h && assoc_p (var))
653 nhash = assoc_create (h->nbuckets);
654 }
655
656 last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0;
657
658 #if ASSOC_KVPAIR_ASSIGNMENT
659 if (assoc_p (var) && kvpair_assignment_p (nlist))
660 {
661 iflags = flags & ~ASS_APPEND;
662 assign_assoc_from_kvlist (var, nlist, nhash, iflags);
663 if (nhash && nhash != h)
664 {
665 h = assoc_cell (var);
666 var_setassoc (var, nhash);
667 assoc_dispose (h);
668 }
669 return;
670 }
671 #endif
672
673 for (list = nlist; list; list = list->next)
674 {
675 /* Don't allow var+=(values) to make assignments in VALUES append to
676 existing values by default. */
677 iflags = flags & ~ASS_APPEND;
678 w = list->word->word;
679
680 /* We have a word of the form [ind]=value */
681 if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
682 {
683 /* Don't have to handle embedded quotes specially any more, since
684 associative array subscripts have not been expanded yet (see
685 above). */
686 len = skipsubscript (w, 0, 0);
687
688 /* XXX - changes for `+=' */
689 if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
690 {
691 if (assoc_p (var))
692 {
693 err_badarraysub (w);
694 continue;
695 }
696 nval = make_variable_value (var, w, flags);
697 if (var->assign_func)
698 (*var->assign_func) (var, nval, last_ind, 0);
699 else
700 array_insert (a, last_ind, nval);
701 FREE (nval);
702 last_ind++;
703 continue;
704 }
705
706 if (len == 1)
707 {
708 err_badarraysub (w);
709 continue;
710 }
711
712 if (ALL_ELEMENT_SUB (w[1]) && len == 2)
713 {
714 set_exit_status (EXECUTION_FAILURE);
715 if (assoc_p (var))
716 report_error (_("%s: invalid associative array key"), w);
717 else
718 report_error (_("%s: cannot assign to non-numeric index"), w);
719 continue;
720 }
721
722 if (array_p (var))
723 {
724 ind = array_expand_index (var, w + 1, len, 0);
725 /* negative subscripts to indexed arrays count back from end */
726 if (ind < 0)
727 ind = array_max_index (array_cell (var)) + 1 + ind;
728 if (ind < 0)
729 {
730 err_badarraysub (w);
731 continue;
732 }
733
734 last_ind = ind;
735 }
736 else if (assoc_p (var))
737 {
738 /* This is not performed above, see expand_compound_array_assignment */
739 w[len] = '\0'; /*[*/
740 akey = expand_assignment_string_to_string (w+1, 0);
741 w[len] = ']';
742 /* And we need to expand the value also, see below */
743 if (akey == 0 || *akey == 0)
744 {
745 err_badarraysub (w);
746 FREE (akey);
747 continue;
748 }
749 }
750
751 /* XXX - changes for `+=' -- just accept the syntax. ksh93 doesn't do this */
752 if (w[len + 1] == '+' && w[len + 2] == '=')
753 {
754 iflags |= ASS_APPEND;
755 val = w + len + 3;
756 }
757 else
758 val = w + len + 2;
759 }
760 else if (assoc_p (var))
761 {
762 set_exit_status (EXECUTION_FAILURE);
763 report_error (_("%s: %s: must use subscript when assigning associative array"), var->name, w);
764 continue;
765 }
766 else /* No [ind]=value, just a stray `=' */
767 {
768 ind = last_ind;
769 val = w;
770 }
771
772 free_val = 0;
773 /* See above; we need to expand the value here */
774 if (assoc_p (var))
775 {
776 val = expand_assignment_string_to_string (val, 0);
777 if (val == 0)
778 {
779 val = (char *)xmalloc (1);
780 val[0] = '\0'; /* like do_assignment_internal */
781 }
782 free_val = 1;
783 }
784
785 savecmd = this_command_name;
786 if (integer_p (var))
787 this_command_name = (char *)NULL; /* no command name for errors */
788 if (assoc_p (var))
789 bind_assoc_var_internal (var, nhash, akey, val, iflags);
790 else
791 bind_array_var_internal (var, ind, akey, val, iflags);
792 last_ind++;
793 this_command_name = savecmd;
794
795 if (free_val)
796 free (val);
797 }
798
799 if (assoc_p (var) && nhash && nhash != h)
800 {
801 h = assoc_cell (var);
802 var_setassoc (var, nhash);
803 assoc_dispose (h);
804 }
805 }
806
807 /* Perform a compound array assignment: VAR->name=( VALUE ). The
808 VALUE has already had the parentheses stripped. */
809 SHELL_VAR *
810 assign_array_var_from_string (var, value, flags)
811 SHELL_VAR *var;
812 char *value;
813 int flags;
814 {
815 WORD_LIST *nlist;
816
817 if (value == 0)
818 return var;
819
820 nlist = expand_compound_array_assignment (var, value, flags);
821 assign_compound_array_list (var, nlist, flags);
822
823 if (nlist)
824 dispose_words (nlist);
825
826 if (var)
827 VUNSETATTR (var, att_invisible); /* no longer invisible */
828
829 return (var);
830 }
831
832 /* Quote globbing chars and characters in $IFS before the `=' in an assignment
833 statement (usually a compound array assignment) to protect them from
834 unwanted filename expansion or word splitting. */
835 static char *
836 quote_assign (string)
837 const char *string;
838 {
839 size_t slen;
840 int saw_eq;
841 char *temp, *t, *subs;
842 const char *s, *send;
843 int ss, se;
844 DECLARE_MBSTATE;
845
846 slen = strlen (string);
847 send = string + slen;
848
849 t = temp = (char *)xmalloc (slen * 2 + 1);
850 saw_eq = 0;
851 for (s = string; *s; )
852 {
853 if (*s == '=')
854 saw_eq = 1;
855 if (saw_eq == 0 && *s == '[') /* looks like a subscript */
856 {
857 ss = s - string;
858 se = skipsubscript (string, ss, 0);
859 subs = substring (s, ss, se);
860 *t++ = '\\';
861 strcpy (t, subs);
862 t += se - ss;
863 *t++ = '\\';
864 *t++ = ']';
865 s += se + 1;
866 free (subs);
867 continue;
868 }
869 if (saw_eq == 0 && (glob_char_p (s) || isifs (*s)))
870 *t++ = '\\';
871
872 COPY_CHAR_P (t, s, send);
873 }
874 *t = '\0';
875 return temp;
876 }
877
878 /* Take a word W of the form [IND]=VALUE and transform it to ['IND']='VALUE'
879 to prevent further expansion. This is called for compound assignments to
880 indexed arrays. W has already undergone word expansions. If W has no [IND]=,
881 just single-quote and return it. */
882 static char *
883 quote_compound_array_word (w, type)
884 char *w;
885 int type;
886 {
887 char *nword, *sub, *value, *t;
888 int ind, wlen, i;
889
890 if (w[0] != LBRACK)
891 return (sh_single_quote (w));
892 ind = skipsubscript (w, 0, 0);
893 if (w[ind] != RBRACK)
894 return (sh_single_quote (w));
895
896 wlen = strlen (w);
897 w[ind] = '\0';
898 sub = sh_single_quote (w+1);
899 w[ind] = RBRACK;
900
901 nword = xmalloc (wlen * 4 + 5); /* wlen*4 is max single quoted length */
902 nword[0] = LBRACK;
903 i = STRLEN (sub);
904 memcpy (nword+1, sub, i);
905 i++; /* accommodate the opening LBRACK */
906 nword[i++] = w[ind++]; /* RBRACK */
907 if (w[ind] == '+')
908 nword[i++] = w[ind++];
909 nword[i++] = w[ind++];
910 value = sh_single_quote (w + ind);
911 strcpy (nword + i, value);
912
913 return nword;
914 }
915
916 /* Expand the key and value in W, which is of the form [KEY]=VALUE, and
917 reconstruct W with the expanded and single-quoted version:
918 ['expanded-key']='expanded-value'. If there is no [KEY]=, single-quote the
919 word and return it. Very similar to previous function, but does not assume
920 W has already been expanded, and expands the KEY and VALUE separately.
921 Used for compound assignments to associative arrays that are arguments to
922 declaration builtins (declare -A a=( list )). */
923 char *
924 expand_and_quote_assoc_word (w, type)
925 char *w;
926 int type;
927 {
928 char *nword, *key, *value, *t;
929 int ind, wlen, i;
930
931 if (w[0] != LBRACK)
932 return (sh_single_quote (w));
933 ind = skipsubscript (w, 0, 0);
934 if (w[ind] != RBRACK)
935 return (sh_single_quote (w));
936
937 w[ind] = '\0';
938 t = expand_assignment_string_to_string (w+1, 0);
939 w[ind] = RBRACK;
940 key = sh_single_quote (t ? t : "");
941 free (t);
942
943 wlen = STRLEN (key);
944 nword = xmalloc (wlen + 5);
945 nword[0] = LBRACK;
946 memcpy (nword+1, key, wlen);
947 i = wlen + 1; /* accommodate the opening LBRACK */
948
949 nword[i++] = w[ind++]; /* RBRACK */
950 if (w[ind] == '+')
951 nword[i++] = w[ind++];
952 nword[i++] = w[ind++];
953
954 t = expand_assignment_string_to_string (w+ind, 0);
955 value = sh_single_quote (t ? t : "");
956 free (t);
957 nword = xrealloc (nword, wlen + 5 + STRLEN (value));
958 strcpy (nword + i, value);
959
960 free (key);
961 free (value);
962
963 return nword;
964 }
965
966 /* For each word in a compound array assignment, if the word looks like
967 [ind]=value, single-quote ind and value, but leave the brackets and
968 the = sign (and any `+') alone. If it's not an assignment, just single-
969 quote the word. This is used for indexed arrays. */
970 void
971 quote_compound_array_list (list, type)
972 WORD_LIST *list;
973 int type;
974 {
975 char *t;
976 WORD_LIST *l;
977
978 for (l = list; l; l = l->next)
979 {
980 if (l->word == 0 || l->word->word == 0)
981 continue; /* should not happen, but just in case... */
982 if ((l->word->flags & W_ASSIGNMENT) == 0)
983 t = sh_single_quote (l->word->word);
984 else
985 t = quote_compound_array_word (l->word->word, type);
986 free (l->word->word);
987 l->word->word = t;
988 }
989 }
990
991 /* For each word in a compound array assignment, if the word looks like
992 [ind]=value, quote globbing chars and characters in $IFS before the `='. */
993 static void
994 quote_array_assignment_chars (list)
995 WORD_LIST *list;
996 {
997 char *nword;
998 WORD_LIST *l;
999
1000 for (l = list; l; l = l->next)
1001 {
1002 if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
1003 continue; /* should not happen, but just in case... */
1004 /* Don't bother if it hasn't been recognized as an assignment or
1005 doesn't look like [ind]=value */
1006 if ((l->word->flags & W_ASSIGNMENT) == 0)
1007 continue;
1008 if (l->word->word[0] != '[' || mbschr (l->word->word, '=') == 0) /* ] */
1009 continue;
1010
1011 nword = quote_assign (l->word->word);
1012 free (l->word->word);
1013 l->word->word = nword;
1014 l->word->flags |= W_NOGLOB; /* XXX - W_NOSPLIT also? */
1015 }
1016 }
1017
1018 /* skipsubscript moved to subst.c to use private functions. 2009/02/24. */
1019
1020 /* This function is called with SUB pointing to just after the beginning
1021 `[' of an array subscript and removes the array element to which SUB
1022 expands from array VAR. A subscript of `*' or `@' unsets the array. */
1023 /* If FLAGS&1 we don't expand the subscript; we just use it as-is. */
1024 int
1025 unbind_array_element (var, sub, flags)
1026 SHELL_VAR *var;
1027 char *sub;
1028 int flags;
1029 {
1030 int len;
1031 arrayind_t ind;
1032 char *akey;
1033 ARRAY_ELEMENT *ae;
1034
1035 len = skipsubscript (sub, 0, (flags&1) || (var && assoc_p(var))); /* XXX */
1036 if (sub[len] != ']' || len == 0)
1037 {
1038 builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg));
1039 return -1;
1040 }
1041 sub[len] = '\0';
1042
1043 if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0)
1044 {
1045 if (array_p (var) || assoc_p (var))
1046 {
1047 unbind_variable (var->name); /* XXX -- {array,assoc}_flush ? */
1048 return (0);
1049 }
1050 else
1051 return -2; /* don't allow this to unset scalar variables */
1052 }
1053
1054 if (assoc_p (var))
1055 {
1056 akey = (flags & 1) ? sub : expand_assignment_string_to_string (sub, 0);
1057 if (akey == 0 || *akey == 0)
1058 {
1059 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
1060 FREE (akey);
1061 return -1;
1062 }
1063 assoc_remove (assoc_cell (var), akey);
1064 if (akey != sub)
1065 free (akey);
1066 }
1067 else if (array_p (var))
1068 {
1069 ind = array_expand_index (var, sub, len+1, 0);
1070 /* negative subscripts to indexed arrays count back from end */
1071 if (ind < 0)
1072 ind = array_max_index (array_cell (var)) + 1 + ind;
1073 if (ind < 0)
1074 {
1075 builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
1076 return -1;
1077 }
1078 ae = array_remove (array_cell (var), ind);
1079 if (ae)
1080 array_dispose_element (ae);
1081 }
1082 else /* array_p (var) == 0 && assoc_p (var) == 0 */
1083 {
1084 akey = this_command_name;
1085 ind = array_expand_index (var, sub, len+1, 0);
1086 this_command_name = akey;
1087 if (ind == 0)
1088 {
1089 unbind_variable (var->name);
1090 return (0);
1091 }
1092 else
1093 return -2; /* any subscript other than 0 is invalid with scalar variables */
1094 }
1095
1096 return 0;
1097 }
1098
1099 /* Format and output an array assignment in compound form VAR=(VALUES),
1100 suitable for re-use as input. */
1101 void
1102 print_array_assignment (var, quoted)
1103 SHELL_VAR *var;
1104 int quoted;
1105 {
1106 char *vstr;
1107
1108 vstr = array_to_assign (array_cell (var), quoted);
1109
1110 if (vstr == 0)
1111 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
1112 else
1113 {
1114 printf ("%s=%s\n", var->name, vstr);
1115 free (vstr);
1116 }
1117 }
1118
1119 /* Format and output an associative array assignment in compound form
1120 VAR=(VALUES), suitable for re-use as input. */
1121 void
1122 print_assoc_assignment (var, quoted)
1123 SHELL_VAR *var;
1124 int quoted;
1125 {
1126 char *vstr;
1127
1128 vstr = assoc_to_assign (assoc_cell (var), quoted);
1129
1130 if (vstr == 0)
1131 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
1132 else
1133 {
1134 printf ("%s=%s\n", var->name, vstr);
1135 free (vstr);
1136 }
1137 }
1138
1139 /***********************************************************************/
1140 /* */
1141 /* Utility functions to manage arrays and their contents for expansion */
1142 /* */
1143 /***********************************************************************/
1144
1145 /* Return 1 if NAME is a properly-formed array reference v[sub]. */
1146
1147 /* We need to reserve 1 for FLAGS, which we pass to skipsubscript. */
1148 int
1149 valid_array_reference (name, flags)
1150 const char *name;
1151 int flags;
1152 {
1153 char *t;
1154 int r, len, isassoc;
1155 SHELL_VAR *entry;
1156
1157 t = mbschr (name, '['); /* ] */
1158 isassoc = 0;
1159 if (t)
1160 {
1161 *t = '\0';
1162 r = legal_identifier (name);
1163 if (flags & VA_NOEXPAND) /* Don't waste a lookup if we don't need one */
1164 isassoc = (entry = find_variable (name)) && assoc_p (entry);
1165 *t = '[';
1166 if (r == 0)
1167 return 0;
1168
1169 if (isassoc && ((flags & (VA_NOEXPAND|VA_ONEWORD)) == (VA_NOEXPAND|VA_ONEWORD)))
1170 len = strlen (t) - 1;
1171 else if (isassoc)
1172 len = skipsubscript (t, 0, flags&VA_NOEXPAND); /* VA_NOEXPAND must be 1 */
1173 else
1174 /* Check for a properly-terminated non-null subscript. */
1175 len = skipsubscript (t, 0, 0); /* arithmetic expression */
1176
1177 if (t[len] != ']' || len == 1 || t[len+1] != '\0')
1178 return 0;
1179
1180 #if 0
1181 /* Could check and allow subscripts consisting only of whitespace for
1182 existing associative arrays, using isassoc */
1183 for (r = 1; r < len; r++)
1184 if (whitespace (t[r]) == 0)
1185 return 1;
1186 return 0;
1187 #else
1188 /* This allows blank subscripts */
1189 return 1;
1190 #endif
1191 }
1192 return 0;
1193 }
1194
1195 /* Expand the array index beginning at S and extending LEN characters. */
1196 arrayind_t
1197 array_expand_index (var, s, len, flags)
1198 SHELL_VAR *var;
1199 char *s;
1200 int len;
1201 int flags;
1202 {
1203 char *exp, *t, *savecmd;
1204 int expok;
1205 arrayind_t val;
1206
1207 exp = (char *)xmalloc (len);
1208 strncpy (exp, s, len - 1);
1209 exp[len - 1] = '\0';
1210 #if 0 /* TAG: maybe bash-5.2 */
1211 if ((flags & AV_NOEXPAND) == 0)
1212 t = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH|Q_ARRAYSUB); /* XXX - Q_ARRAYSUB for future use */
1213 else
1214 t = exp;
1215 #endif
1216 t = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH|Q_ARRAYSUB); /* XXX - Q_ARRAYSUB for future use */
1217 savecmd = this_command_name;
1218 this_command_name = (char *)NULL;
1219 val = evalexp (t, EXP_EXPANDED, &expok); /* XXX - was 0 but we expanded exp already */
1220 this_command_name = savecmd;
1221 if (t != exp)
1222 free (t);
1223 free (exp);
1224 if (expok == 0)
1225 {
1226 set_exit_status (EXECUTION_FAILURE);
1227
1228 if (no_longjmp_on_fatal_error)
1229 return 0;
1230 top_level_cleanup ();
1231 jump_to_top_level (DISCARD);
1232 }
1233 return val;
1234 }
1235
1236 /* Return the name of the variable specified by S without any subscript.
1237 If SUBP is non-null, return a pointer to the start of the subscript
1238 in *SUBP. If LENP is non-null, the length of the subscript is returned
1239 in *LENP. This returns newly-allocated memory. */
1240 char *
1241 array_variable_name (s, flags, subp, lenp)
1242 const char *s;
1243 int flags;
1244 char **subp;
1245 int *lenp;
1246 {
1247 char *t, *ret;
1248 int ind, ni;
1249
1250 t = mbschr (s, '[');
1251 if (t == 0)
1252 {
1253 if (subp)
1254 *subp = t;
1255 if (lenp)
1256 *lenp = 0;
1257 return ((char *)NULL);
1258 }
1259 ind = t - s;
1260 ni = skipsubscript (s, ind, flags); /* XXX - was 0 not flags */
1261 if (ni <= ind + 1 || s[ni] != ']')
1262 {
1263 err_badarraysub (s);
1264 if (subp)
1265 *subp = t;
1266 if (lenp)
1267 *lenp = 0;
1268 return ((char *)NULL);
1269 }
1270
1271 *t = '\0';
1272 ret = savestring (s);
1273 *t++ = '['; /* ] */
1274
1275 if (subp)
1276 *subp = t;
1277 if (lenp)
1278 *lenp = ni - ind;
1279
1280 return ret;
1281 }
1282
1283 /* Return the variable specified by S without any subscript. If SUBP is
1284 non-null, return a pointer to the start of the subscript in *SUBP.
1285 If LENP is non-null, the length of the subscript is returned in *LENP. */
1286 SHELL_VAR *
1287 array_variable_part (s, flags, subp, lenp)
1288 const char *s;
1289 int flags;
1290 char **subp;
1291 int *lenp;
1292 {
1293 char *t;
1294 SHELL_VAR *var;
1295
1296 t = array_variable_name (s, flags, subp, lenp);
1297 if (t == 0)
1298 return ((SHELL_VAR *)NULL);
1299 var = find_variable (t); /* XXX - handle namerefs here? */
1300
1301 free (t);
1302 return var; /* now return invisible variables; caller must handle */
1303 }
1304
1305 #define INDEX_ERROR() \
1306 do \
1307 { \
1308 if (var) \
1309 err_badarraysub (var->name); \
1310 else \
1311 { \
1312 t[-1] = '\0'; \
1313 err_badarraysub (s); \
1314 t[-1] = '['; /* ] */\
1315 } \
1316 return ((char *)NULL); \
1317 } \
1318 while (0)
1319
1320 /* Return a string containing the elements in the array and subscript
1321 described by S. If the subscript is * or @, obeys quoting rules akin
1322 to the expansion of $* and $@ including double quoting. If RTYPE
1323 is non-null it gets 1 if the array reference is name[*], 2 if the
1324 reference is name[@], and 0 otherwise. */
1325 static char *
1326 array_value_internal (s, quoted, flags, rtype, indp)
1327 const char *s;
1328 int quoted, flags, *rtype;
1329 arrayind_t *indp;
1330 {
1331 int len;
1332 arrayind_t ind;
1333 char *akey;
1334 char *retval, *t, *temp;
1335 WORD_LIST *l;
1336 SHELL_VAR *var;
1337
1338 var = array_variable_part (s, (flags&AV_NOEXPAND) ? 1 : 0, &t, &len); /* XXX */
1339
1340 /* Expand the index, even if the variable doesn't exist, in case side
1341 effects are needed, like ${w[i++]} where w is unset. */
1342 #if 0
1343 if (var == 0)
1344 return (char *)NULL;
1345 #endif
1346
1347 if (len == 0)
1348 return ((char *)NULL); /* error message already printed */
1349
1350 /* [ */
1351 akey = 0;
1352 if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
1353 {
1354 if (rtype)
1355 *rtype = (t[0] == '*') ? 1 : 2;
1356 if ((flags & AV_ALLOWALL) == 0)
1357 {
1358 err_badarraysub (s);
1359 return ((char *)NULL);
1360 }
1361 else if (var == 0 || value_cell (var) == 0) /* XXX - check for invisible_p(var) ? */
1362 return ((char *)NULL);
1363 else if (invisible_p (var))
1364 return ((char *)NULL);
1365 else if (array_p (var) == 0 && assoc_p (var) == 0)
1366 l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
1367 else if (assoc_p (var))
1368 {
1369 l = assoc_to_word_list (assoc_cell (var));
1370 if (l == (WORD_LIST *)NULL)
1371 return ((char *)NULL);
1372 }
1373 else
1374 {
1375 l = array_to_word_list (array_cell (var));
1376 if (l == (WORD_LIST *)NULL)
1377 return ((char *) NULL);
1378 }
1379
1380 /* Caller of array_value takes care of inspecting rtype and duplicating
1381 retval if rtype == 0, so this is not a memory leak */
1382 if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
1383 {
1384 temp = string_list_dollar_star (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0);
1385 retval = quote_string (temp);
1386 free (temp);
1387 }
1388 else /* ${name[@]} or unquoted ${name[*]} */
1389 retval = string_list_dollar_at (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0);
1390
1391 dispose_words (l);
1392 }
1393 else
1394 {
1395 if (rtype)
1396 *rtype = 0;
1397 if (var == 0 || array_p (var) || assoc_p (var) == 0)
1398 {
1399 if ((flags & AV_USEIND) == 0 || indp == 0)
1400 {
1401 ind = array_expand_index (var, t, len, flags);
1402 if (ind < 0)
1403 {
1404 /* negative subscripts to indexed arrays count back from end */
1405 if (var && array_p (var))
1406 ind = array_max_index (array_cell (var)) + 1 + ind;
1407 if (ind < 0)
1408 INDEX_ERROR();
1409 }
1410 if (indp)
1411 *indp = ind;
1412 }
1413 else if (indp)
1414 ind = *indp;
1415 }
1416 else if (assoc_p (var))
1417 {
1418 t[len - 1] = '\0';
1419 if ((flags & AV_NOEXPAND) == 0)
1420 akey = expand_assignment_string_to_string (t, 0); /* [ */
1421 else
1422 akey = savestring (t);
1423 t[len - 1] = ']';
1424 if (akey == 0 || *akey == 0)
1425 {
1426 FREE (akey);
1427 INDEX_ERROR();
1428 }
1429 }
1430
1431 if (var == 0 || value_cell (var) == 0) /* XXX - check invisible_p(var) ? */
1432 {
1433 FREE (akey);
1434 return ((char *)NULL);
1435 }
1436 else if (invisible_p (var))
1437 {
1438 FREE (akey);
1439 return ((char *)NULL);
1440 }
1441 if (array_p (var) == 0 && assoc_p (var) == 0)
1442 return (ind == 0 ? value_cell (var) : (char *)NULL);
1443 else if (assoc_p (var))
1444 {
1445 retval = assoc_reference (assoc_cell (var), akey);
1446 free (akey);
1447 }
1448 else
1449 retval = array_reference (array_cell (var), ind);
1450 }
1451
1452 return retval;
1453 }
1454
1455 /* Return a string containing the elements described by the array and
1456 subscript contained in S, obeying quoting for subscripts * and @. */
1457 char *
1458 array_value (s, quoted, flags, rtype, indp)
1459 const char *s;
1460 int quoted, flags, *rtype;
1461 arrayind_t *indp;
1462 {
1463 return (array_value_internal (s, quoted, flags|AV_ALLOWALL, rtype, indp));
1464 }
1465
1466 /* Return the value of the array indexing expression S as a single string.
1467 If (FLAGS & AV_ALLOWALL) is 0, do not allow `@' and `*' subscripts. This
1468 is used by other parts of the shell such as the arithmetic expression
1469 evaluator in expr.c. */
1470 char *
1471 get_array_value (s, flags, rtype, indp)
1472 const char *s;
1473 int flags, *rtype;
1474 arrayind_t *indp;
1475 {
1476 return (array_value_internal (s, 0, flags, rtype, indp));
1477 }
1478
1479 char *
1480 array_keys (s, quoted, pflags)
1481 char *s;
1482 int quoted, pflags;
1483 {
1484 int len;
1485 char *retval, *t, *temp;
1486 WORD_LIST *l;
1487 SHELL_VAR *var;
1488
1489 var = array_variable_part (s, 0, &t, &len);
1490
1491 /* [ */
1492 if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']')
1493 return (char *)NULL;
1494
1495 if (var_isset (var) == 0 || invisible_p (var))
1496 return (char *)NULL;
1497
1498 if (array_p (var) == 0 && assoc_p (var) == 0)
1499 l = add_string_to_list ("0", (WORD_LIST *)NULL);
1500 else if (assoc_p (var))
1501 l = assoc_keys_to_word_list (assoc_cell (var));
1502 else
1503 l = array_keys_to_word_list (array_cell (var));
1504 if (l == (WORD_LIST *)NULL)
1505 return ((char *) NULL);
1506
1507 retval = string_list_pos_params (t[0], l, quoted, pflags);
1508
1509 dispose_words (l);
1510 return retval;
1511 }
1512 #endif /* ARRAY_VARS */