1 /* arrayfunc.c -- High-level array functions used by other parts of the shell. */
3 /* Copyright (C) 2001 Free Software Foundation, Inc.
5 This file is part of GNU Bash, the Bourne Again SHell.
7 Bash is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with Bash; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
23 #if defined (ARRAY_VARS)
25 #if defined (HAVE_UNISTD_H)
31 #include "builtins/common.h"
33 extern char *this_command_name;
34 extern int last_command_exit_value;
36 static void quote_array_assignment_chars __P((WORD_LIST *));
37 static char *array_value_internal __P((char *, int, int));
39 /* **************************************************************** */
41 /* Functions to manipulate array variables and perform assignments */
43 /* **************************************************************** */
45 /* Convert a shell variable to an array variable. The original value is
48 convert_var_to_array (var)
54 oldval = value_cell (var);
56 array_add_element (array, 0, oldval);
58 FREE (value_cell (var));
59 var->value = (char *)array;
61 INVALIDATE_EXPORTSTR (var);
63 VSETATTR (var, att_array);
64 VUNSETATTR (var, att_invisible);
69 /* Perform an array assignment name[ind]=value. If NAME already exists and
70 is not an array, and IND is 0, perform name=value instead. If NAME exists
71 and is not an array, and IND is not 0, convert it into an array with the
72 existing value as name[0].
74 If NAME does not exist, just create an array variable, no matter what
75 IND's value may be. */
77 bind_array_variable (name, ind, value)
85 entry = var_lookup (name, shell_variables);
87 if (entry == (SHELL_VAR *) 0)
88 entry = make_new_array_variable (name);
89 else if (readonly_p (entry) || noassign_p (entry))
91 if (readonly_p (entry))
92 report_error ("%s: readonly variable", name);
95 else if (array_p (entry) == 0)
96 entry = convert_var_to_array (entry);
98 /* ENTRY is an array variable, and ARRAY points to the value. */
99 newval = make_variable_value (entry, value);
100 if (entry->assign_func)
101 (*entry->assign_func) (entry, ind, newval);
103 array_add_element (array_cell (entry), ind, newval);
109 /* Parse NAME, a lhs of an assignment statement of the form v[s], and
110 assign VALUE to that array element by calling bind_array_variable(). */
112 assign_array_element (name, value)
120 vname = array_variable_name (name, &sub, &sublen);
123 return ((SHELL_VAR *)NULL);
125 if ((ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']') || (sublen <= 1))
128 report_error ("%s: bad array subscript", name);
129 return ((SHELL_VAR *)NULL);
132 ind = array_expand_index (sub, sublen);
136 report_error ("%s: bad array subscript", name);
137 return ((SHELL_VAR *)NULL);
140 entry = bind_array_variable (vname, ind, value);
146 /* Find the array variable corresponding to NAME. If there is no variable,
147 create a new array variable. If the variable exists but is not an array,
148 convert it to an indexed array. If CHECK_FLAGS is non-zero, an existing
149 variable is checked for the readonly or noassign attribute in preparation
150 for assignment (e.g., by the `read' builtin). */
152 find_or_make_array_variable (name, check_flags)
158 var = find_variable (name);
161 var = make_new_array_variable (name);
162 else if (check_flags && (readonly_p (var) || noassign_p (var)))
164 if (readonly_p (var))
165 report_error ("%s: readonly variable", name);
166 return ((SHELL_VAR *)NULL);
168 else if (array_p (var) == 0)
169 var = convert_var_to_array (var);
174 /* Perform a compound assignment statement for array NAME, where VALUE is
175 the text between the parens: NAME=( VALUE ) */
177 assign_array_from_string (name, value)
182 var = find_or_make_array_variable (name, 1);
184 return ((SHELL_VAR *)NULL);
186 return (assign_array_var_from_string (var, value));
189 /* Sequentially assign the indices of indexed array variable VAR from the
192 assign_array_var_from_word_list (var, list)
196 register arrayind_t i;
197 register WORD_LIST *l;
200 for (a = array_cell (var), l = list, i = 0; l; l = l->next, i++)
201 if (var->assign_func)
202 (*var->assign_func) (var, i, l->word->word);
204 array_add_element (a, i, l->word->word);
208 /* Perform a compound array assignment: VAR->name=( VALUE ). The
209 VALUE has already had the parentheses stripped. */
211 assign_array_var_from_string (var, value)
216 WORD_LIST *list, *nlist;
217 char *w, *val, *nval;
219 arrayind_t ind, last_ind;
224 /* If this is called from declare_builtin, value[0] == '(' and
225 strchr(value, ')') != 0. In this case, we need to extract
226 the value from between the parens before going on. */
227 if (*value == '(') /*)*/
230 val = extract_array_assignment_list (value, &ni);
237 /* Expand the value string into a list of words, performing all the
238 shell expansions including pathname generation and word splitting. */
239 /* First we split the string on whitespace, using the shell parser
240 (ksh93 seems to do this). */
241 list = parse_string_to_word_list (val, "array assign");
243 /* If we're using [subscript]=value, we need to quote each [ and ] to
244 prevent unwanted filename expansion. */
246 quote_array_assignment_chars (list);
248 /* Now that we've split it, perform the shell expansions on each
250 nlist = list ? expand_words_no_vars (list) : (WORD_LIST *)NULL;
252 dispose_words (list);
257 a = array_cell (var);
259 /* Now that we are ready to assign values to the array, kill the existing
264 for (last_ind = 0, list = nlist; list; list = list->next)
266 w = list->word->word;
268 /* We have a word of the form [ind]=value */
271 len = skipsubscript (w, 0);
273 if (w[len] != ']' || w[len+1] != '=')
275 nval = make_variable_value (var, w);
276 if (var->assign_func)
277 (*var->assign_func) (var, last_ind, nval);
279 array_add_element (a, last_ind, nval);
287 report_error ("%s: bad array subscript", w);
291 if (ALL_ELEMENT_SUB (w[1]) && len == 2)
293 report_error ("%s: cannot assign to non-numeric index", w);
297 ind = array_expand_index (w + 1, len);
300 report_error ("%s: bad array subscript", w);
306 else /* No [ind]=value, just a stray `=' */
313 this_command_name = (char *)NULL; /* no command name for errors */
314 nval = make_variable_value (var, val);
315 if (var->assign_func)
316 (*var->assign_func) (var, ind, nval);
318 array_add_element (a, ind, nval);
323 dispose_words (nlist);
327 /* For each word in a compound array assignment, if the word looks like
328 [ind]=value, quote the `[' and `]' before the `=' to protect them from
329 unwanted filename expansion. */
331 quote_array_assignment_chars (list)
338 for (l = list; l; l = l->next)
340 if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
341 continue; /* should not happen, but just in case... */
342 /* Don't bother if it doesn't look like [ind]=value */
343 if (l->word->word[0] != '[' || strchr (l->word->word, '=') == 0) /* ] */
345 s = nword = (char *)xmalloc (strlen (l->word->word) * 2 + 1);
347 for (t = l->word->word; *t; )
351 if (saw_eq == 0 && (*t == '[' || *t == ']'))
356 free (l->word->word);
357 l->word->word = nword;
361 /* This function assumes s[i] == '['; returns with s[ret] == ']' if
362 an array subscript is correctly parsed. */
370 for (count = 1; count && (c = s[++i]); )
380 /* This function is called with SUB pointing to just after the beginning
381 `[' of an array subscript and removes the array element to which SUB
382 expands from array VAR. A subscript of `*' or `@' unsets the array. */
384 unbind_array_element (var, sub)
392 len = skipsubscript (sub, 0);
393 if (sub[len] != ']' || len == 0)
395 builtin_error ("%s[%s: bad array subscript", var->name, sub);
400 if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0)
402 makunbound (var->name, shell_variables);
405 ind = array_expand_index (sub, len+1);
408 builtin_error ("[%s]: bad array subscript", sub);
411 ae = array_delete_element (array_cell (var), ind);
413 destroy_array_element (ae);
417 /* Format and output an array assignment in compound form VAR=(VALUES),
418 suitable for re-use as input. */
420 print_array_assignment (var, quoted)
427 vstr = quoted_array_assignment_string (array_cell (var));
429 vstr = array_to_assignment_string (array_cell (var));
432 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
435 printf ("%s=%s\n", var->name, vstr);
440 /***********************************************************************/
442 /* Utility functions to manage arrays and their contents for expansion */
444 /***********************************************************************/
446 /* Return 1 if NAME is a properly-formed array reference v[sub]. */
448 valid_array_reference (name)
454 t = strchr (name, '['); /* ] */
458 r = legal_identifier (name);
462 /* Check for a properly-terminated non-blank subscript. */
463 len = skipsubscript (t, 0);
464 if (t[len] != ']' || len == 1)
466 for (r = 1; r < len; r++)
467 if (whitespace (t[r]) == 0)
474 /* Expand the array index beginning at S and extending LEN characters. */
476 array_expand_index (s, len)
484 exp = (char *)xmalloc (len);
485 strncpy (exp, s, len - 1);
487 t = expand_string_to_string (exp, 0);
488 this_command_name = (char *)NULL;
489 val = evalexp (t, &expok);
494 last_command_exit_value = EXECUTION_FAILURE;
495 jump_to_top_level (DISCARD);
500 /* Return the name of the variable specified by S without any subscript.
501 If SUBP is non-null, return a pointer to the start of the subscript
502 in *SUBP. If LENP is non-null, the length of the subscript is returned
503 in *LENP. This returns newly-allocated memory. */
505 array_variable_name (s, subp, lenp)
514 return ((char *)NULL);
516 ni = skipsubscript (s, ind);
517 if (ni <= ind + 1 || s[ni] != ']')
519 report_error ("%s: bad array subscript", s);
520 return ((char *)NULL);
524 ret = savestring (s);
535 /* Return the variable specified by S without any subscript. If SUBP is
536 non-null, return a pointer to the start of the subscript in *SUBP.
537 If LENP is non-null, the length of the subscript is returned in *LENP. */
539 array_variable_part (s, subp, lenp)
546 t = array_variable_name (s, subp, lenp);
548 return ((SHELL_VAR *)NULL);
549 var = find_variable (t);
555 /* Return a string containing the elements in the array and subscript
556 described by S. If the subscript is * or @, obeys quoting rules akin
557 to the expansion of $* and $@ including double quoting. */
559 array_value_internal (s, quoted, allow_all)
561 int quoted, allow_all;
565 char *retval, *t, *temp;
569 var = array_variable_part (s, &t, &len);
575 if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
579 report_error ("%s: bad array subscript", s);
580 return ((char *)NULL);
582 else if (array_p (var) == 0)
584 l = (WORD_LIST *)NULL;
585 l = add_string_to_list (value_cell (var), l);
589 l = array_to_word_list (array_cell (var));
590 if (l == (WORD_LIST *)NULL)
591 return ((char *) NULL);
594 if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
596 temp = string_list_dollar_star (l);
597 retval = quote_string (temp);
600 else /* ${name[@]} or unquoted ${name[*]} */
601 retval = string_list_dollar_at (l, quoted);
607 ind = array_expand_index (t, len);
610 report_error ("%s: bad array subscript", var->name);
611 return ((char *)NULL);
613 if (array_p (var) == 0)
614 return (ind == 0 ? savestring (value_cell (var)) : (char *)NULL);
615 retval = array_reference (array_cell (var), ind);
617 retval = quote_escapes (retval);
623 /* Return a string containing the elements described by the array and
624 subscript contained in S, obeying quoting for subscripts * and @. */
626 array_value (s, quoted)
630 return (array_value_internal (s, quoted, 1));
633 /* Return the value of the array indexing expression S as a single string.
634 If ALLOW_ALL is 0, do not allow `@' and `*' subscripts. This is used
635 by other parts of the shell such as the arithmetic expression evaluator
638 get_array_value (s, allow_all)
642 return (array_value_internal (s, 0, allow_all));
645 #endif /* ARRAY_VARS */