Line data Source code
1 : /* arrayfunc.c -- High-level array functions used by other parts of the shell. */
2 :
3 : /* Copyright (C) 2001-2016 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 "pathexp.h"
34 :
35 : #include "shmbutil.h"
36 : #if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
37 : # include <mbstr.h> /* mbschr */
38 : #endif
39 :
40 : #include "builtins/common.h"
41 :
42 : extern char *this_command_name;
43 : extern int last_command_exit_value;
44 : extern int array_needs_making;
45 :
46 : static SHELL_VAR *bind_array_var_internal __P((SHELL_VAR *, arrayind_t, char *, char *, int));
47 : static SHELL_VAR *assign_array_element_internal __P((SHELL_VAR *, char *, char *, char *, int, char *, int));
48 :
49 : static char *quote_assign __P((const char *));
50 : static void quote_array_assignment_chars __P((WORD_LIST *));
51 : static char *array_value_internal __P((const char *, int, int, int *, arrayind_t *));
52 :
53 : /* Standard error message to use when encountering an invalid array subscript */
54 : const char * const bash_badsub_errmsg = N_("bad array subscript");
55 :
56 : /* **************************************************************** */
57 : /* */
58 : /* Functions to manipulate array variables and perform assignments */
59 : /* */
60 : /* **************************************************************** */
61 :
62 : /* Convert a shell variable to an array variable. The original value is
63 : saved as array[0]. */
64 : SHELL_VAR *
65 0 : convert_var_to_array (var)
66 : SHELL_VAR *var;
67 : {
68 0 : char *oldval;
69 0 : ARRAY *array;
70 :
71 0 : oldval = value_cell (var);
72 0 : array = array_create ();
73 0 : if (oldval)
74 0 : array_insert (array, 0, oldval);
75 :
76 0 : FREE (value_cell (var));
77 0 : var_setarray (var, array);
78 :
79 : /* these aren't valid anymore */
80 0 : var->dynamic_value = (sh_var_value_func_t *)NULL;
81 0 : var->assign_func = (sh_var_assign_func_t *)NULL;
82 :
83 0 : INVALIDATE_EXPORTSTR (var);
84 0 : if (exported_p (var))
85 0 : array_needs_making++;
86 :
87 0 : VSETATTR (var, att_array);
88 0 : VUNSETATTR (var, att_invisible);
89 :
90 : /* Make sure it's not marked as an associative array any more */
91 0 : VUNSETATTR (var, att_assoc);
92 :
93 : /* Since namerefs can't be array variables, turn off nameref attribute */
94 0 : VUNSETATTR (var, att_nameref);
95 :
96 0 : return var;
97 : }
98 :
99 : /* Convert a shell variable to an array variable. The original value is
100 : saved as array[0]. */
101 : SHELL_VAR *
102 0 : convert_var_to_assoc (var)
103 : SHELL_VAR *var;
104 : {
105 0 : char *oldval;
106 0 : HASH_TABLE *hash;
107 :
108 0 : oldval = value_cell (var);
109 0 : hash = assoc_create (0);
110 0 : if (oldval)
111 0 : assoc_insert (hash, savestring ("0"), oldval);
112 :
113 0 : FREE (value_cell (var));
114 0 : var_setassoc (var, hash);
115 :
116 : /* these aren't valid anymore */
117 0 : var->dynamic_value = (sh_var_value_func_t *)NULL;
118 0 : var->assign_func = (sh_var_assign_func_t *)NULL;
119 :
120 0 : INVALIDATE_EXPORTSTR (var);
121 0 : if (exported_p (var))
122 0 : array_needs_making++;
123 :
124 0 : VSETATTR (var, att_assoc);
125 0 : VUNSETATTR (var, att_invisible);
126 :
127 : /* Make sure it's not marked as an indexed array any more */
128 0 : VUNSETATTR (var, att_array);
129 :
130 : /* Since namerefs can't be array variables, turn off nameref attribute */
131 0 : VUNSETATTR (var, att_nameref);
132 :
133 0 : return var;
134 : }
135 :
136 : char *
137 27 : make_array_variable_value (entry, ind, key, value, flags)
138 : SHELL_VAR *entry;
139 : arrayind_t ind;
140 : char *key;
141 : char *value;
142 : int flags;
143 : {
144 27 : SHELL_VAR *dentry;
145 27 : char *newval;
146 :
147 : /* If we're appending, we need the old value of the array reference, so
148 : fake out make_variable_value with a dummy SHELL_VAR */
149 27 : if (flags & ASS_APPEND)
150 : {
151 0 : dentry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
152 0 : dentry->name = savestring (entry->name);
153 0 : if (assoc_p (entry))
154 0 : newval = assoc_reference (assoc_cell (entry), key);
155 : else
156 0 : newval = array_reference (array_cell (entry), ind);
157 0 : if (newval)
158 0 : dentry->value = savestring (newval);
159 : else
160 : {
161 0 : dentry->value = (char *)xmalloc (1);
162 0 : dentry->value[0] = '\0';
163 : }
164 0 : dentry->exportstr = 0;
165 0 : dentry->attributes = entry->attributes & ~(att_array|att_assoc|att_exported);
166 : /* Leave the rest of the members uninitialized; the code doesn't look
167 : at them. */
168 0 : newval = make_variable_value (dentry, value, flags);
169 0 : dispose_variable (dentry);
170 : }
171 : else
172 27 : newval = make_variable_value (entry, value, flags);
173 :
174 27 : return newval;
175 : }
176 :
177 : static SHELL_VAR *
178 27 : bind_array_var_internal (entry, ind, key, value, flags)
179 : SHELL_VAR *entry;
180 : arrayind_t ind;
181 : char *key;
182 : char *value;
183 : int flags;
184 : {
185 27 : char *newval;
186 :
187 27 : newval = make_array_variable_value (entry, ind, key, value, flags);
188 :
189 27 : if (entry->assign_func)
190 0 : (*entry->assign_func) (entry, newval, ind, key);
191 27 : else if (assoc_p (entry))
192 0 : assoc_insert (assoc_cell (entry), key, newval);
193 : else
194 27 : array_insert (array_cell (entry), ind, newval);
195 27 : FREE (newval);
196 :
197 27 : VUNSETATTR (entry, att_invisible); /* no longer invisible */
198 27 : return (entry);
199 : }
200 :
201 : /* Perform an array assignment name[ind]=value. If NAME already exists and
202 : is not an array, and IND is 0, perform name=value instead. If NAME exists
203 : and is not an array, and IND is not 0, convert it into an array with the
204 : existing value as name[0].
205 :
206 : If NAME does not exist, just create an array variable, no matter what
207 : IND's value may be. */
208 : SHELL_VAR *
209 9 : bind_array_variable (name, ind, value, flags)
210 : char *name;
211 : arrayind_t ind;
212 : char *value;
213 : int flags;
214 : {
215 9 : SHELL_VAR *entry;
216 :
217 9 : entry = find_shell_variable (name);
218 :
219 9 : if (entry == (SHELL_VAR *) 0)
220 : {
221 : /* Is NAME a nameref variable that points to an unset variable? */
222 9 : entry = find_variable_nameref_for_create (name, 0);
223 9 : if (entry == INVALID_NAMEREF_VALUE)
224 : return ((SHELL_VAR *)0);
225 9 : if (entry && nameref_p (entry))
226 0 : entry = make_new_array_variable (nameref_cell (entry));
227 : }
228 9 : if (entry == (SHELL_VAR *) 0)
229 9 : entry = make_new_array_variable (name);
230 0 : else if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry))
231 : {
232 0 : if (readonly_p (entry))
233 0 : err_readonly (name);
234 0 : return (entry);
235 : }
236 0 : else if (array_p (entry) == 0)
237 0 : entry = convert_var_to_array (entry);
238 :
239 : /* ENTRY is an array variable, and ARRAY points to the value. */
240 9 : return (bind_array_var_internal (entry, ind, 0, value, flags));
241 : }
242 :
243 : SHELL_VAR *
244 0 : bind_array_element (entry, ind, value, flags)
245 : SHELL_VAR *entry;
246 : arrayind_t ind;
247 : char *value;
248 : int flags;
249 : {
250 0 : return (bind_array_var_internal (entry, ind, 0, value, flags));
251 : }
252 :
253 : SHELL_VAR *
254 0 : bind_assoc_variable (entry, name, key, value, flags)
255 : SHELL_VAR *entry;
256 : char *name;
257 : char *key;
258 : char *value;
259 : int flags;
260 : {
261 0 : if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry))
262 : {
263 0 : if (readonly_p (entry))
264 0 : err_readonly (name);
265 0 : return (entry);
266 : }
267 :
268 0 : return (bind_array_var_internal (entry, 0, key, value, flags));
269 : }
270 :
271 : /* Parse NAME, a lhs of an assignment statement of the form v[s], and
272 : assign VALUE to that array element by calling bind_array_variable(). */
273 : SHELL_VAR *
274 9 : assign_array_element (name, value, flags)
275 : char *name, *value;
276 : int flags;
277 : {
278 9 : char *sub, *vname;
279 9 : int sublen;
280 9 : SHELL_VAR *entry;
281 :
282 9 : vname = array_variable_name (name, &sub, &sublen);
283 :
284 9 : if (vname == 0)
285 : return ((SHELL_VAR *)NULL);
286 :
287 9 : if ((ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']') || (sublen <= 1))
288 : {
289 0 : free (vname);
290 0 : err_badarraysub (name);
291 0 : return ((SHELL_VAR *)NULL);
292 : }
293 :
294 9 : entry = find_variable (vname);
295 9 : entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags);
296 :
297 9 : free (vname);
298 9 : return entry;
299 : }
300 :
301 : static SHELL_VAR *
302 9 : assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
303 : SHELL_VAR *entry;
304 : char *name; /* only used for error messages */
305 : char *vname;
306 : char *sub;
307 : int sublen;
308 : char *value;
309 : int flags;
310 : {
311 9 : char *akey;
312 9 : arrayind_t ind;
313 :
314 9 : if (entry && assoc_p (entry))
315 : {
316 0 : sub[sublen-1] = '\0';
317 0 : akey = expand_assignment_string_to_string (sub, 0); /* [ */
318 0 : sub[sublen-1] = ']';
319 0 : if (akey == 0 || *akey == 0)
320 : {
321 0 : err_badarraysub (name);
322 0 : FREE (akey);
323 0 : return ((SHELL_VAR *)NULL);
324 : }
325 0 : entry = bind_assoc_variable (entry, vname, akey, value, flags);
326 : }
327 : else
328 : {
329 9 : ind = array_expand_index (entry, sub, sublen);
330 : /* negative subscripts to indexed arrays count back from end */
331 9 : if (entry && ind < 0)
332 0 : ind = (array_p (entry) ? array_max_index (array_cell (entry)) : 0) + 1 + ind;
333 9 : if (ind < 0)
334 : {
335 0 : err_badarraysub (name);
336 0 : return ((SHELL_VAR *)NULL);
337 : }
338 9 : entry = bind_array_variable (vname, ind, value, flags);
339 : }
340 :
341 : return (entry);
342 : }
343 :
344 : /* Find the array variable corresponding to NAME. If there is no variable,
345 : create a new array variable. If the variable exists but is not an array,
346 : convert it to an indexed array. If FLAGS&1 is non-zero, an existing
347 : variable is checked for the readonly or noassign attribute in preparation
348 : for assignment (e.g., by the `read' builtin). If FLAGS&2 is non-zero, we
349 : create an associative array. */
350 : SHELL_VAR *
351 18 : find_or_make_array_variable (name, flags)
352 : char *name;
353 : int flags;
354 : {
355 18 : SHELL_VAR *var;
356 :
357 18 : var = find_variable (name);
358 18 : if (var == 0)
359 : {
360 : /* See if we have a nameref pointing to a variable that hasn't been
361 : created yet. */
362 18 : var = find_variable_last_nameref (name, 1);
363 18 : if (var && nameref_p (var) && invisible_p (var))
364 : {
365 0 : internal_warning (_("%s: removing nameref attribute"), name);
366 0 : VUNSETATTR (var, att_nameref);
367 : }
368 18 : if (var && nameref_p (var))
369 : {
370 0 : if (valid_nameref_value (nameref_cell (var), 2) == 0)
371 : {
372 0 : sh_invalidid (nameref_cell (var));
373 0 : return ((SHELL_VAR *)NULL);
374 : }
375 0 : var = (flags & 2) ? make_new_assoc_variable (nameref_cell (var)) : make_new_array_variable (nameref_cell (var));
376 : }
377 : }
378 :
379 18 : if (var == 0)
380 18 : var = (flags & 2) ? make_new_assoc_variable (name) : make_new_array_variable (name);
381 0 : else if ((flags & 1) && (readonly_p (var) || noassign_p (var)))
382 : {
383 0 : if (readonly_p (var))
384 0 : err_readonly (name);
385 0 : return ((SHELL_VAR *)NULL);
386 : }
387 0 : else if ((flags & 2) && array_p (var))
388 : {
389 0 : last_command_exit_value = 1;
390 0 : report_error (_("%s: cannot convert indexed to associative array"), name);
391 0 : return ((SHELL_VAR *)NULL);
392 : }
393 0 : else if (array_p (var) == 0 && assoc_p (var) == 0)
394 0 : var = convert_var_to_array (var);
395 :
396 : return (var);
397 : }
398 :
399 : /* Perform a compound assignment statement for array NAME, where VALUE is
400 : the text between the parens: NAME=( VALUE ) */
401 : SHELL_VAR *
402 18 : assign_array_from_string (name, value, flags)
403 : char *name, *value;
404 : int flags;
405 : {
406 18 : SHELL_VAR *var;
407 18 : int vflags;
408 :
409 18 : vflags = 1;
410 18 : if (flags & ASS_MKASSOC)
411 0 : vflags |= 2;
412 :
413 18 : var = find_or_make_array_variable (name, vflags);
414 18 : if (var == 0)
415 : return ((SHELL_VAR *)NULL);
416 :
417 18 : return (assign_array_var_from_string (var, value, flags));
418 : }
419 :
420 : /* Sequentially assign the indices of indexed array variable VAR from the
421 : words in LIST. */
422 : SHELL_VAR *
423 0 : assign_array_var_from_word_list (var, list, flags)
424 : SHELL_VAR *var;
425 : WORD_LIST *list;
426 : int flags;
427 : {
428 0 : register arrayind_t i;
429 0 : register WORD_LIST *l;
430 0 : ARRAY *a;
431 :
432 0 : a = array_cell (var);
433 0 : i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
434 :
435 0 : for (l = list; l; l = l->next, i++)
436 0 : bind_array_var_internal (var, i, 0, l->word->word, flags & ~ASS_APPEND);
437 :
438 0 : VUNSETATTR (var, att_invisible); /* no longer invisible */
439 :
440 0 : return var;
441 : }
442 :
443 : WORD_LIST *
444 18 : expand_compound_array_assignment (var, value, flags)
445 : SHELL_VAR *var;
446 : char *value;
447 : int flags;
448 : {
449 18 : WORD_LIST *list, *nlist;
450 18 : char *val;
451 18 : int ni;
452 :
453 : /* This condition is true when invoked from the declare builtin with a
454 : command like
455 : declare -a d='([1]="" [2]="bdef" [5]="hello world" "test")' */
456 18 : if (*value == '(') /*)*/
457 : {
458 0 : ni = 1;
459 0 : val = extract_array_assignment_list (value, &ni);
460 0 : if (val == 0)
461 : return (WORD_LIST *)NULL;
462 : }
463 : else
464 : val = value;
465 :
466 : /* Expand the value string into a list of words, performing all the
467 : shell expansions including pathname generation and word splitting. */
468 : /* First we split the string on whitespace, using the shell parser
469 : (ksh93 seems to do this). */
470 18 : list = parse_string_to_word_list (val, 1, "array assign");
471 :
472 18 : if (var && assoc_p (var))
473 : {
474 0 : if (val != value)
475 0 : free (val);
476 0 : return list;
477 : }
478 :
479 : /* If we're using [subscript]=value, we need to quote each [ and ] to
480 : prevent unwanted filename expansion. This doesn't need to be done
481 : for associative array expansion, since that uses a different expansion
482 : function (see assign_compound_array_list below). */
483 18 : if (list)
484 9 : quote_array_assignment_chars (list);
485 :
486 : /* Now that we've split it, perform the shell expansions on each
487 : word in the list. */
488 18 : nlist = list ? expand_words_no_vars (list) : (WORD_LIST *)NULL;
489 :
490 18 : dispose_words (list);
491 :
492 18 : if (val != value)
493 0 : free (val);
494 :
495 : return nlist;
496 : }
497 :
498 : /* Callers ensure that VAR is not NULL */
499 : void
500 18 : assign_compound_array_list (var, nlist, flags)
501 : SHELL_VAR *var;
502 : WORD_LIST *nlist;
503 : int flags;
504 : {
505 18 : ARRAY *a;
506 18 : HASH_TABLE *h;
507 18 : WORD_LIST *list;
508 18 : char *w, *val, *nval, *savecmd;
509 18 : int len, iflags, free_val;
510 18 : arrayind_t ind, last_ind;
511 18 : char *akey;
512 :
513 18 : a = (var && array_p (var)) ? array_cell (var) : (ARRAY *)0;
514 18 : h = (var && assoc_p (var)) ? assoc_cell (var) : (HASH_TABLE *)0;
515 :
516 18 : akey = (char *)0;
517 18 : ind = 0;
518 :
519 : /* Now that we are ready to assign values to the array, kill the existing
520 : value. */
521 18 : if ((flags & ASS_APPEND) == 0)
522 : {
523 18 : if (a && array_p (var))
524 18 : array_flush (a);
525 0 : else if (h && assoc_p (var))
526 0 : assoc_flush (h);
527 : }
528 :
529 18 : last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0;
530 :
531 36 : for (list = nlist; list; list = list->next)
532 : {
533 : /* Don't allow var+=(values) to make assignments in VALUES append to
534 : existing values by default. */
535 18 : iflags = flags & ~ASS_APPEND;
536 18 : w = list->word->word;
537 :
538 : /* We have a word of the form [ind]=value */
539 18 : if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
540 : {
541 : /* Don't have to handle embedded quotes specially any more, since
542 : associative array subscripts have not been expanded yet (see
543 : above). */
544 0 : len = skipsubscript (w, 0, 0);
545 :
546 : /* XXX - changes for `+=' */
547 0 : if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
548 : {
549 0 : if (assoc_p (var))
550 : {
551 0 : err_badarraysub (w);
552 0 : continue;
553 : }
554 0 : nval = make_variable_value (var, w, flags);
555 0 : if (var->assign_func)
556 0 : (*var->assign_func) (var, nval, last_ind, 0);
557 : else
558 0 : array_insert (a, last_ind, nval);
559 0 : FREE (nval);
560 0 : last_ind++;
561 0 : continue;
562 : }
563 :
564 0 : if (len == 1)
565 : {
566 0 : err_badarraysub (w);
567 0 : continue;
568 : }
569 :
570 0 : if (ALL_ELEMENT_SUB (w[1]) && len == 2)
571 : {
572 0 : last_command_exit_value = 1;
573 0 : if (assoc_p (var))
574 0 : report_error (_("%s: invalid associative array key"), w);
575 : else
576 0 : report_error (_("%s: cannot assign to non-numeric index"), w);
577 0 : continue;
578 : }
579 :
580 0 : if (array_p (var))
581 : {
582 0 : ind = array_expand_index (var, w + 1, len);
583 : /* negative subscripts to indexed arrays count back from end */
584 0 : if (ind < 0)
585 0 : ind = array_max_index (array_cell (var)) + 1 + ind;
586 0 : if (ind < 0)
587 : {
588 0 : err_badarraysub (w);
589 0 : continue;
590 : }
591 :
592 : last_ind = ind;
593 : }
594 0 : else if (assoc_p (var))
595 : {
596 : /* This is not performed above, see expand_compound_array_assignment */
597 0 : w[len] = '\0'; /*[*/
598 0 : akey = expand_assignment_string_to_string (w+1, 0);
599 0 : w[len] = ']';
600 : /* And we need to expand the value also, see below */
601 0 : if (akey == 0 || *akey == 0)
602 : {
603 0 : err_badarraysub (w);
604 0 : FREE (akey);
605 0 : continue;
606 : }
607 : }
608 :
609 : /* XXX - changes for `+=' -- just accept the syntax. ksh93 doesn't do this */
610 0 : if (w[len + 1] == '+' && w[len + 2] == '=')
611 : {
612 0 : iflags |= ASS_APPEND;
613 0 : val = w + len + 3;
614 : }
615 : else
616 0 : val = w + len + 2;
617 : }
618 18 : else if (assoc_p (var))
619 : {
620 0 : last_command_exit_value = 1;
621 0 : report_error (_("%s: %s: must use subscript when assigning associative array"), var->name, w);
622 0 : continue;
623 : }
624 : else /* No [ind]=value, just a stray `=' */
625 : {
626 : ind = last_ind;
627 : val = w;
628 : }
629 :
630 18 : free_val = 0;
631 : /* See above; we need to expand the value here */
632 18 : if (assoc_p (var))
633 : {
634 0 : val = expand_assignment_string_to_string (val, 0);
635 0 : if (val == 0)
636 : {
637 0 : val = (char *)xmalloc (1);
638 0 : val[0] = '\0'; /* like do_assignment_internal */
639 : }
640 : free_val = 1;
641 : }
642 :
643 18 : savecmd = this_command_name;
644 18 : if (integer_p (var))
645 0 : this_command_name = (char *)NULL; /* no command name for errors */
646 18 : bind_array_var_internal (var, ind, akey, val, iflags);
647 18 : last_ind++;
648 18 : this_command_name = savecmd;
649 :
650 18 : if (free_val)
651 0 : free (val);
652 : }
653 18 : }
654 :
655 : /* Perform a compound array assignment: VAR->name=( VALUE ). The
656 : VALUE has already had the parentheses stripped. */
657 : SHELL_VAR *
658 18 : assign_array_var_from_string (var, value, flags)
659 : SHELL_VAR *var;
660 : char *value;
661 : int flags;
662 : {
663 18 : WORD_LIST *nlist;
664 :
665 18 : if (value == 0)
666 : return var;
667 :
668 18 : nlist = expand_compound_array_assignment (var, value, flags);
669 18 : assign_compound_array_list (var, nlist, flags);
670 :
671 18 : if (nlist)
672 9 : dispose_words (nlist);
673 :
674 18 : if (var)
675 18 : VUNSETATTR (var, att_invisible); /* no longer invisible */
676 :
677 : return (var);
678 : }
679 :
680 : /* Quote globbing chars and characters in $IFS before the `=' in an assignment
681 : statement (usually a compound array assignment) to protect them from
682 : unwanted filename expansion or word splitting. */
683 : static char *
684 0 : quote_assign (string)
685 : const char *string;
686 : {
687 0 : size_t slen;
688 0 : int saw_eq;
689 0 : char *temp, *t, *subs;
690 0 : const char *s, *send;
691 0 : int ss, se;
692 0 : DECLARE_MBSTATE;
693 :
694 0 : slen = strlen (string);
695 0 : send = string + slen;
696 :
697 0 : t = temp = (char *)xmalloc (slen * 2 + 1);
698 0 : saw_eq = 0;
699 0 : for (s = string; *s; )
700 : {
701 0 : if (*s == '=')
702 : saw_eq = 1;
703 0 : if (saw_eq == 0 && *s == '[') /* looks like a subscript */
704 : {
705 0 : ss = s - string;
706 0 : se = skipsubscript (string, ss, 0);
707 0 : subs = substring (s, ss, se);
708 0 : *t++ = '\\';
709 0 : strcpy (t, subs);
710 0 : t += se - ss;
711 0 : *t++ = '\\';
712 0 : *t++ = ']';
713 0 : s += se + 1;
714 0 : free (subs);
715 0 : continue;
716 : }
717 0 : if (saw_eq == 0 && (glob_char_p (s) || isifs (*s)))
718 0 : *t++ = '\\';
719 :
720 0 : COPY_CHAR_P (t, s, send);
721 : }
722 0 : *t = '\0';
723 0 : return temp;
724 : }
725 :
726 : /* For each word in a compound array assignment, if the word looks like
727 : [ind]=value, quote globbing chars and characters in $IFS before the `='. */
728 : static void
729 9 : quote_array_assignment_chars (list)
730 : WORD_LIST *list;
731 : {
732 9 : char *nword;
733 9 : WORD_LIST *l;
734 :
735 27 : for (l = list; l; l = l->next)
736 : {
737 18 : if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
738 : continue; /* should not happen, but just in case... */
739 : /* Don't bother if it hasn't been recognized as an assignment or
740 : doesn't look like [ind]=value */
741 18 : if ((l->word->flags & W_ASSIGNMENT) == 0)
742 : continue;
743 0 : if (l->word->word[0] != '[' || mbschr (l->word->word, '=') == 0) /* ] */
744 0 : continue;
745 :
746 0 : nword = quote_assign (l->word->word);
747 0 : free (l->word->word);
748 0 : l->word->word = nword;
749 0 : l->word->flags |= W_NOGLOB; /* XXX - W_NOSPLIT also? */
750 : }
751 9 : }
752 :
753 : /* skipsubscript moved to subst.c to use private functions. 2009/02/24. */
754 :
755 : /* This function is called with SUB pointing to just after the beginning
756 : `[' of an array subscript and removes the array element to which SUB
757 : expands from array VAR. A subscript of `*' or `@' unsets the array. */
758 : int
759 0 : unbind_array_element (var, sub)
760 : SHELL_VAR *var;
761 : char *sub;
762 : {
763 0 : int len;
764 0 : arrayind_t ind;
765 0 : char *akey;
766 0 : ARRAY_ELEMENT *ae;
767 :
768 0 : len = skipsubscript (sub, 0, (var && assoc_p(var)));
769 0 : if (sub[len] != ']' || len == 0)
770 : {
771 0 : builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg));
772 0 : return -1;
773 : }
774 0 : sub[len] = '\0';
775 :
776 0 : if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0)
777 : {
778 0 : if (array_p (var) || assoc_p (var))
779 : {
780 0 : unbind_variable (var->name); /* XXX -- {array,assoc}_flush ? */
781 0 : return (0);
782 : }
783 : else
784 : return -2; /* don't allow this to unset scalar variables */
785 : }
786 :
787 0 : if (assoc_p (var))
788 : {
789 0 : akey = expand_assignment_string_to_string (sub, 0); /* [ */
790 0 : if (akey == 0 || *akey == 0)
791 : {
792 0 : builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
793 0 : FREE (akey);
794 0 : return -1;
795 : }
796 0 : assoc_remove (assoc_cell (var), akey);
797 0 : free (akey);
798 : }
799 0 : else if (array_p (var))
800 : {
801 0 : ind = array_expand_index (var, sub, len+1);
802 : /* negative subscripts to indexed arrays count back from end */
803 0 : if (ind < 0)
804 0 : ind = array_max_index (array_cell (var)) + 1 + ind;
805 0 : if (ind < 0)
806 : {
807 0 : builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
808 0 : return -1;
809 : }
810 0 : ae = array_remove (array_cell (var), ind);
811 0 : if (ae)
812 0 : array_dispose_element (ae);
813 : }
814 : else /* array_p (var) == 0 && assoc_p (var) == 0 */
815 : {
816 0 : akey = this_command_name;
817 0 : ind = array_expand_index (var, sub, len+1);
818 0 : this_command_name = akey;
819 0 : if (ind == 0)
820 : {
821 0 : unbind_variable (var->name);
822 0 : return (0);
823 : }
824 : else
825 : return -2; /* any subscript other than 0 is invalid with scalar variables */
826 : }
827 :
828 : return 0;
829 : }
830 :
831 : /* Format and output an array assignment in compound form VAR=(VALUES),
832 : suitable for re-use as input. */
833 : void
834 1481 : print_array_assignment (var, quoted)
835 : SHELL_VAR *var;
836 : int quoted;
837 : {
838 1481 : char *vstr;
839 :
840 1481 : vstr = array_to_assign (array_cell (var), quoted);
841 :
842 1481 : if (vstr == 0)
843 2148 : printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
844 : else
845 : {
846 407 : printf ("%s=%s\n", var->name, vstr);
847 407 : free (vstr);
848 : }
849 1481 : }
850 :
851 : /* Format and output an associative array assignment in compound form
852 : VAR=(VALUES), suitable for re-use as input. */
853 : void
854 358 : print_assoc_assignment (var, quoted)
855 : SHELL_VAR *var;
856 : int quoted;
857 : {
858 358 : char *vstr;
859 :
860 358 : vstr = assoc_to_assign (assoc_cell (var), quoted);
861 :
862 358 : if (vstr == 0)
863 716 : printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
864 : else
865 : {
866 0 : printf ("%s=%s\n", var->name, vstr);
867 0 : free (vstr);
868 : }
869 358 : }
870 :
871 : /***********************************************************************/
872 : /* */
873 : /* Utility functions to manage arrays and their contents for expansion */
874 : /* */
875 : /***********************************************************************/
876 :
877 : /* Return 1 if NAME is a properly-formed array reference v[sub]. */
878 : int
879 28622100 : valid_array_reference (name, flags)
880 : const char *name;
881 : int flags;
882 : {
883 28622100 : char *t;
884 28622100 : int r, len;
885 :
886 28622100 : t = mbschr (name, '['); /* ] */
887 28622100 : if (t)
888 : {
889 93 : *t = '\0';
890 93 : r = legal_identifier (name);
891 93 : *t = '[';
892 93 : if (r == 0)
893 : return 0;
894 : /* Check for a properly-terminated non-blank subscript. */
895 66 : len = skipsubscript (t, 0, 0);
896 66 : if (t[len] != ']' || len == 1)
897 : return 0;
898 44 : if (t[len+1] != '\0')
899 : return 0;
900 44 : for (r = 1; r < len; r++)
901 44 : if (whitespace (t[r]) == 0)
902 : return 1;
903 : return 0;
904 : }
905 : return 0;
906 : }
907 :
908 : /* Expand the array index beginning at S and extending LEN characters. */
909 : arrayind_t
910 9 : array_expand_index (var, s, len)
911 : SHELL_VAR *var;
912 : char *s;
913 : int len;
914 : {
915 9 : char *exp, *t, *savecmd;
916 9 : int expok;
917 9 : arrayind_t val;
918 :
919 9 : exp = (char *)xmalloc (len);
920 9 : strncpy (exp, s, len - 1);
921 9 : exp[len - 1] = '\0';
922 9 : t = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH|Q_ARRAYSUB); /* XXX - Q_ARRAYSUB for future use */
923 9 : savecmd = this_command_name;
924 9 : this_command_name = (char *)NULL;
925 9 : val = evalexp (t, &expok);
926 9 : this_command_name = savecmd;
927 9 : free (t);
928 9 : free (exp);
929 9 : if (expok == 0)
930 : {
931 0 : last_command_exit_value = EXECUTION_FAILURE;
932 :
933 0 : if (no_longjmp_on_fatal_error)
934 : return 0;
935 0 : top_level_cleanup ();
936 0 : jump_to_top_level (DISCARD);
937 : }
938 : return val;
939 : }
940 :
941 : /* Return the name of the variable specified by S without any subscript.
942 : If SUBP is non-null, return a pointer to the start of the subscript
943 : in *SUBP. If LENP is non-null, the length of the subscript is returned
944 : in *LENP. This returns newly-allocated memory. */
945 : char *
946 20 : array_variable_name (s, subp, lenp)
947 : const char *s;
948 : char **subp;
949 : int *lenp;
950 : {
951 20 : char *t, *ret;
952 20 : int ind, ni;
953 :
954 20 : t = mbschr (s, '[');
955 20 : if (t == 0)
956 : {
957 0 : if (subp)
958 0 : *subp = t;
959 0 : if (lenp)
960 0 : *lenp = 0;
961 0 : return ((char *)NULL);
962 : }
963 20 : ind = t - s;
964 20 : ni = skipsubscript (s, ind, 0);
965 20 : if (ni <= ind + 1 || s[ni] != ']')
966 : {
967 0 : err_badarraysub (s);
968 0 : if (subp)
969 0 : *subp = t;
970 0 : if (lenp)
971 0 : *lenp = 0;
972 0 : return ((char *)NULL);
973 : }
974 :
975 20 : *t = '\0';
976 20 : ret = savestring (s);
977 20 : *t++ = '['; /* ] */
978 :
979 20 : if (subp)
980 20 : *subp = t;
981 20 : if (lenp)
982 20 : *lenp = ni - ind;
983 :
984 : return ret;
985 : }
986 :
987 : /* Return the variable specified by S without any subscript. If SUBP is
988 : non-null, return a pointer to the start of the subscript in *SUBP.
989 : If LENP is non-null, the length of the subscript is returned in *LENP. */
990 : SHELL_VAR *
991 11 : array_variable_part (s, subp, lenp)
992 : const char *s;
993 : char **subp;
994 : int *lenp;
995 : {
996 11 : char *t;
997 11 : SHELL_VAR *var;
998 :
999 11 : t = array_variable_name (s, subp, lenp);
1000 11 : if (t == 0)
1001 : return ((SHELL_VAR *)NULL);
1002 11 : var = find_variable (t); /* XXX - handle namerefs here? */
1003 :
1004 11 : free (t);
1005 11 : return var; /* now return invisible variables; caller must handle */
1006 : }
1007 :
1008 : #define INDEX_ERROR() \
1009 : do \
1010 : { \
1011 : if (var) \
1012 : err_badarraysub (var->name); \
1013 : else \
1014 : { \
1015 : t[-1] = '\0'; \
1016 : err_badarraysub (s); \
1017 : t[-1] = '['; /* ] */\
1018 : } \
1019 : return ((char *)NULL); \
1020 : } \
1021 : while (0)
1022 :
1023 : /* Return a string containing the elements in the array and subscript
1024 : described by S. If the subscript is * or @, obeys quoting rules akin
1025 : to the expansion of $* and $@ including double quoting. If RTYPE
1026 : is non-null it gets 1 if the array reference is name[*], 2 if the
1027 : reference is name[@], and 0 otherwise. */
1028 : static char *
1029 11 : array_value_internal (s, quoted, flags, rtype, indp)
1030 : const char *s;
1031 : int quoted, flags, *rtype;
1032 : arrayind_t *indp;
1033 : {
1034 11 : int len;
1035 11 : arrayind_t ind = 0;
1036 11 : char *akey;
1037 11 : char *retval, *t, *temp;
1038 11 : WORD_LIST *l;
1039 11 : SHELL_VAR *var;
1040 :
1041 11 : var = array_variable_part (s, &t, &len);
1042 :
1043 : /* Expand the index, even if the variable doesn't exist, in case side
1044 : effects are needed, like ${w[i++]} where w is unset. */
1045 : #if 0
1046 : if (var == 0)
1047 : return (char *)NULL;
1048 : #endif
1049 :
1050 11 : if (len == 0)
1051 : return ((char *)NULL); /* error message already printed */
1052 :
1053 : /* [ */
1054 11 : akey = 0;
1055 11 : if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
1056 : {
1057 11 : if (rtype)
1058 11 : *rtype = (t[0] == '*') ? 1 : 2;
1059 11 : if ((flags & AV_ALLOWALL) == 0)
1060 : {
1061 0 : err_badarraysub (s);
1062 0 : return ((char *)NULL);
1063 : }
1064 11 : else if (var == 0 || value_cell (var) == 0) /* XXX - check for invisible_p(var) ? */
1065 : return ((char *)NULL);
1066 0 : else if (array_p (var) == 0 && assoc_p (var) == 0)
1067 0 : l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
1068 0 : else if (assoc_p (var))
1069 : {
1070 0 : l = assoc_to_word_list (assoc_cell (var));
1071 0 : if (l == (WORD_LIST *)NULL)
1072 : return ((char *)NULL);
1073 : }
1074 : else
1075 : {
1076 0 : l = array_to_word_list (array_cell (var));
1077 0 : if (l == (WORD_LIST *)NULL)
1078 : return ((char *) NULL);
1079 : }
1080 :
1081 0 : if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
1082 : {
1083 0 : temp = string_list_dollar_star (l);
1084 0 : retval = quote_string (temp); /* XXX - leak here */
1085 0 : free (temp);
1086 : }
1087 : else /* ${name[@]} or unquoted ${name[*]} */
1088 : /* XXX - bash-4.4/bash-5.0 test AV_ASSIGNRHS and pass PF_ASSIGNRHS */
1089 0 : retval = string_list_dollar_at (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0); /* XXX - leak here */
1090 :
1091 0 : dispose_words (l);
1092 : }
1093 : else
1094 : {
1095 0 : if (rtype)
1096 0 : *rtype = 0;
1097 0 : if (var == 0 || array_p (var) || assoc_p (var) == 0)
1098 : {
1099 0 : if ((flags & AV_USEIND) == 0 || indp == 0)
1100 : {
1101 0 : ind = array_expand_index (var, t, len);
1102 0 : if (ind < 0)
1103 : {
1104 : /* negative subscripts to indexed arrays count back from end */
1105 0 : if (var && array_p (var))
1106 0 : ind = array_max_index (array_cell (var)) + 1 + ind;
1107 0 : if (ind < 0)
1108 0 : INDEX_ERROR();
1109 : }
1110 0 : if (indp)
1111 0 : *indp = ind;
1112 : }
1113 0 : else if (indp)
1114 0 : ind = *indp;
1115 : }
1116 0 : else if (assoc_p (var))
1117 : {
1118 0 : t[len - 1] = '\0';
1119 0 : akey = expand_assignment_string_to_string (t, 0); /* [ */
1120 0 : t[len - 1] = ']';
1121 0 : if (akey == 0 || *akey == 0)
1122 : {
1123 0 : FREE (akey);
1124 0 : INDEX_ERROR();
1125 : }
1126 : }
1127 :
1128 0 : if (var == 0 || value_cell (var) == 0) /* XXX - check invisible_p(var) ? */
1129 : {
1130 0 : FREE (akey);
1131 0 : return ((char *)NULL);
1132 : }
1133 0 : if (array_p (var) == 0 && assoc_p (var) == 0)
1134 0 : return (ind == 0 ? value_cell (var) : (char *)NULL);
1135 0 : else if (assoc_p (var))
1136 : {
1137 0 : retval = assoc_reference (assoc_cell (var), akey);
1138 0 : free (akey);
1139 : }
1140 : else
1141 0 : retval = array_reference (array_cell (var), ind);
1142 : }
1143 :
1144 : return retval;
1145 : }
1146 :
1147 : /* Return a string containing the elements described by the array and
1148 : subscript contained in S, obeying quoting for subscripts * and @. */
1149 : char *
1150 11 : array_value (s, quoted, flags, rtype, indp)
1151 : const char *s;
1152 : int quoted, flags, *rtype;
1153 : arrayind_t *indp;
1154 : {
1155 11 : return (array_value_internal (s, quoted, flags|AV_ALLOWALL, rtype, indp));
1156 : }
1157 :
1158 : /* Return the value of the array indexing expression S as a single string.
1159 : If (FLAGS & AV_ALLOWALL) is 0, do not allow `@' and `*' subscripts. This
1160 : is used by other parts of the shell such as the arithmetic expression
1161 : evaluator in expr.c. */
1162 : char *
1163 0 : get_array_value (s, flags, rtype, indp)
1164 : const char *s;
1165 : int flags, *rtype;
1166 : arrayind_t *indp;
1167 : {
1168 0 : return (array_value_internal (s, 0, flags, rtype, indp));
1169 : }
1170 :
1171 : char *
1172 0 : array_keys (s, quoted)
1173 : char *s;
1174 : int quoted;
1175 : {
1176 0 : int len;
1177 0 : char *retval, *t, *temp;
1178 0 : WORD_LIST *l;
1179 0 : SHELL_VAR *var;
1180 :
1181 0 : var = array_variable_part (s, &t, &len);
1182 :
1183 : /* [ */
1184 0 : if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']')
1185 : return (char *)NULL;
1186 :
1187 0 : if (var_isset (var) == 0 || invisible_p (var))
1188 : return (char *)NULL;
1189 :
1190 0 : if (array_p (var) == 0 && assoc_p (var) == 0)
1191 0 : l = add_string_to_list ("0", (WORD_LIST *)NULL);
1192 0 : else if (assoc_p (var))
1193 0 : l = assoc_keys_to_word_list (assoc_cell (var));
1194 : else
1195 0 : l = array_keys_to_word_list (array_cell (var));
1196 0 : if (l == (WORD_LIST *)NULL)
1197 : return ((char *) NULL);
1198 :
1199 0 : if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
1200 : {
1201 0 : temp = string_list_dollar_star (l);
1202 0 : retval = quote_string (temp);
1203 0 : free (temp);
1204 : }
1205 : else /* ${!name[@]} or unquoted ${!name[*]} */
1206 0 : retval = string_list_dollar_at (l, quoted, 0);
1207 :
1208 0 : dispose_words (l);
1209 0 : return retval;
1210 : }
1211 : #endif /* ARRAY_VARS */
|