1 /* arrayfunc.c -- High-level array functions used by other parts of the shell. */
3 /* Copyright (C) 2001-2005 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)
36 #include "builtins/common.h"
38 extern char *this_command_name
;
39 extern int last_command_exit_value
;
40 extern int array_needs_making
;
42 static SHELL_VAR
*bind_array_var_internal
__P((SHELL_VAR
*, arrayind_t
, char *, int));
44 static void quote_array_assignment_chars
__P((WORD_LIST
*));
45 static char *array_value_internal
__P((char *, int, int, int *));
47 /* Standard error message to use when encountering an invalid array subscript */
48 char *bash_badsub_errmsg
= N_("bad array subscript");
50 /* **************************************************************** */
52 /* Functions to manipulate array variables and perform assignments */
54 /* **************************************************************** */
56 /* Convert a shell variable to an array variable. The original value is
59 convert_var_to_array (var
)
65 oldval
= value_cell (var
);
66 array
= array_create ();
68 array_insert (array
, 0, oldval
);
70 FREE (value_cell (var
));
71 var_setarray (var
, array
);
73 /* these aren't valid anymore */
74 var
->dynamic_value
= (sh_var_value_func_t
*)NULL
;
75 var
->assign_func
= (sh_var_assign_func_t
*)NULL
;
77 INVALIDATE_EXPORTSTR (var
);
81 VSETATTR (var
, att_array
);
82 VUNSETATTR (var
, att_invisible
);
88 bind_array_var_internal (entry
, ind
, value
, flags
)
97 /* If we're appending, we need the old value of the array reference, so
98 fake out make_variable_value with a dummy SHELL_VAR */
99 if (flags
& ASS_APPEND
)
101 dentry
= (SHELL_VAR
*)xmalloc (sizeof (SHELL_VAR
));
102 dentry
->name
= savestring (entry
->name
);
103 newval
= array_reference (array_cell (entry
), ind
);
105 dentry
->value
= savestring (newval
);
108 dentry
->value
= (char *)xmalloc (1);
109 dentry
->value
[0] = '\0';
111 dentry
->exportstr
= 0;
112 dentry
->attributes
= entry
->attributes
& ~(att_array
|att_exported
);
113 /* Leave the rest of the members uninitialized; the code doesn't look
115 newval
= make_variable_value (dentry
, value
, flags
);
116 dispose_variable (dentry
);
119 newval
= make_variable_value (entry
, value
, flags
);
121 if (entry
->assign_func
)
122 (*entry
->assign_func
) (entry
, newval
, ind
);
124 array_insert (array_cell (entry
), ind
, newval
);
130 /* Perform an array assignment name[ind]=value. If NAME already exists and
131 is not an array, and IND is 0, perform name=value instead. If NAME exists
132 and is not an array, and IND is not 0, convert it into an array with the
133 existing value as name[0].
135 If NAME does not exist, just create an array variable, no matter what
136 IND's value may be. */
138 bind_array_variable (name
, ind
, value
, flags
)
146 entry
= var_lookup (name
, shell_variables
);
148 if (entry
== (SHELL_VAR
*) 0)
149 entry
= make_new_array_variable (name
);
150 else if (readonly_p (entry
) || noassign_p (entry
))
152 if (readonly_p (entry
))
156 else if (array_p (entry
) == 0)
157 entry
= convert_var_to_array (entry
);
159 /* ENTRY is an array variable, and ARRAY points to the value. */
160 return (bind_array_var_internal (entry
, ind
, value
, flags
));
163 /* Parse NAME, a lhs of an assignment statement of the form v[s], and
164 assign VALUE to that array element by calling bind_array_variable(). */
166 assign_array_element (name
, value
, flags
)
175 vname
= array_variable_name (name
, &sub
, &sublen
);
178 return ((SHELL_VAR
*)NULL
);
180 if ((ALL_ELEMENT_SUB (sub
[0]) && sub
[1] == ']') || (sublen
<= 1))
183 err_badarraysub (name
);
184 return ((SHELL_VAR
*)NULL
);
187 ind
= array_expand_index (sub
, sublen
);
191 err_badarraysub (name
);
192 return ((SHELL_VAR
*)NULL
);
195 entry
= bind_array_variable (vname
, ind
, value
, flags
);
201 /* Find the array variable corresponding to NAME. If there is no variable,
202 create a new array variable. If the variable exists but is not an array,
203 convert it to an indexed array. If CHECK_FLAGS is non-zero, an existing
204 variable is checked for the readonly or noassign attribute in preparation
205 for assignment (e.g., by the `read' builtin). */
207 find_or_make_array_variable (name
, check_flags
)
213 var
= find_variable (name
);
216 var
= make_new_array_variable (name
);
217 else if (check_flags
&& (readonly_p (var
) || noassign_p (var
)))
219 if (readonly_p (var
))
221 return ((SHELL_VAR
*)NULL
);
223 else if (array_p (var
) == 0)
224 var
= convert_var_to_array (var
);
229 /* Perform a compound assignment statement for array NAME, where VALUE is
230 the text between the parens: NAME=( VALUE ) */
232 assign_array_from_string (name
, value
, flags
)
238 var
= find_or_make_array_variable (name
, 1);
240 return ((SHELL_VAR
*)NULL
);
242 return (assign_array_var_from_string (var
, value
, flags
));
245 /* Sequentially assign the indices of indexed array variable VAR from the
248 assign_array_var_from_word_list (var
, list
, flags
)
253 register arrayind_t i
;
254 register WORD_LIST
*l
;
257 a
= array_cell (var
);
258 i
= (flags
& ASS_APPEND
) ? array_max_index (a
) + 1 : 0;
260 for (l
= list
; l
; l
= l
->next
, i
++)
261 if (var
->assign_func
)
262 (*var
->assign_func
) (var
, l
->word
->word
, i
);
264 array_insert (a
, i
, l
->word
->word
);
268 /* Perform a compound array assignment: VAR->name=( VALUE ). The
269 VALUE has already had the parentheses stripped. */
271 assign_array_var_from_string (var
, value
, flags
)
277 WORD_LIST
*list
, *nlist
;
278 char *w
, *val
, *nval
;
280 arrayind_t ind
, last_ind
;
285 /* If this is called from declare_builtin, value[0] == '(' and
286 xstrchr(value, ')') != 0. In this case, we need to extract
287 the value from between the parens before going on. */
288 if (*value
== '(') /*)*/
291 val
= extract_array_assignment_list (value
, &ni
);
298 /* Expand the value string into a list of words, performing all the
299 shell expansions including pathname generation and word splitting. */
300 /* First we split the string on whitespace, using the shell parser
301 (ksh93 seems to do this). */
302 list
= parse_string_to_word_list (val
, 1, "array assign");
304 /* If we're using [subscript]=value, we need to quote each [ and ] to
305 prevent unwanted filename expansion. */
307 quote_array_assignment_chars (list
);
309 /* Now that we've split it, perform the shell expansions on each
311 nlist
= list
? expand_words_no_vars (list
) : (WORD_LIST
*)NULL
;
313 dispose_words (list
);
318 a
= array_cell (var
);
320 /* Now that we are ready to assign values to the array, kill the existing
322 if (a
&& (flags
& ASS_APPEND
) == 0)
324 last_ind
= (flags
& ASS_APPEND
) ? array_max_index (a
) + 1 : 0;
326 for (list
= nlist
; list
; list
= list
->next
)
328 w
= list
->word
->word
;
330 /* We have a word of the form [ind]=value */
331 if ((list
->word
->flags
& W_ASSIGNMENT
) && w
[0] == '[')
333 len
= skipsubscript (w
, 0);
336 /* XXX - changes for `+=' */
337 if (w
[len
] != ']' || (w
[len
+1] != '=' && (w
[len
+1] != '+' || w
[len
+2] != '=')))
339 if (w
[len
] != ']' || w
[len
+1] != '=')
342 nval
= make_variable_value (var
, w
, flags
);
343 if (var
->assign_func
)
344 (*var
->assign_func
) (var
, nval
, last_ind
);
346 array_insert (a
, last_ind
, nval
);
358 if (ALL_ELEMENT_SUB (w
[1]) && len
== 2)
360 report_error (_("%s: cannot assign to non-numeric index"), w
);
364 ind
= array_expand_index (w
+ 1, len
);
371 /* XXX - changes for `+=' */
372 if (w
[len
+ 1] == '+' && w
[len
+ 2] == '=')
380 else /* No [ind]=value, just a stray `=' */
387 this_command_name
= (char *)NULL
; /* no command name for errors */
388 bind_array_var_internal (var
, ind
, val
, flags
);
392 dispose_words (nlist
);
396 /* For each word in a compound array assignment, if the word looks like
397 [ind]=value, quote the `[' and `]' before the `=' to protect them from
398 unwanted filename expansion. */
400 quote_array_assignment_chars (list
)
407 for (l
= list
; l
; l
= l
->next
)
409 if (l
->word
== 0 || l
->word
->word
== 0 || l
->word
->word
[0] == '\0')
410 continue; /* should not happen, but just in case... */
411 /* Don't bother if it doesn't look like [ind]=value */
412 if (l
->word
->word
[0] != '[' || xstrchr (l
->word
->word
, '=') == 0) /* ] */
414 s
= nword
= (char *)xmalloc (strlen (l
->word
->word
) * 2 + 1);
416 for (t
= l
->word
->word
; *t
; )
420 if (saw_eq
== 0 && (*t
== '[' || *t
== ']'))
425 free (l
->word
->word
);
426 l
->word
->word
= nword
;
430 /* This function assumes s[i] == '['; returns with s[ret] == ']' if
431 an array subscript is correctly parsed. */
438 #if defined (HANDLE_MULTIBYTE)
439 mbstate_t state
, state_bak
;
440 size_t slength
, mblength
;
444 #if defined (HANDLE_MULTIBYTE)
445 memset (&state
, '\0', sizeof (mbstate_t));
446 slength
= strlen (s
+ i
);
447 mb_cur_max
= MB_CUR_MAX
;
453 /* Advance one (possibly multibyte) character in S starting at I. */
454 #if defined (HANDLE_MULTIBYTE)
458 mblength
= mbrlen (s
+ i
, slength
, &state
);
460 if (MB_INVALIDCH (mblength
))
466 else if (MB_NULLWCH (mblength
))
491 /* This function is called with SUB pointing to just after the beginning
492 `[' of an array subscript and removes the array element to which SUB
493 expands from array VAR. A subscript of `*' or `@' unsets the array. */
495 unbind_array_element (var
, sub
)
503 len
= skipsubscript (sub
, 0);
504 if (sub
[len
] != ']' || len
== 0)
506 builtin_error ("%s[%s: %s", var
->name
, sub
, _(bash_badsub_errmsg
));
511 if (ALL_ELEMENT_SUB (sub
[0]) && sub
[1] == 0)
513 unbind_variable (var
->name
);
516 ind
= array_expand_index (sub
, len
+1);
519 builtin_error ("[%s]: %s", sub
, _(bash_badsub_errmsg
));
522 ae
= array_remove (array_cell (var
), ind
);
524 array_dispose_element (ae
);
528 /* Format and output an array assignment in compound form VAR=(VALUES),
529 suitable for re-use as input. */
531 print_array_assignment (var
, quoted
)
537 vstr
= array_to_assign (array_cell (var
), quoted
);
540 printf ("%s=%s\n", var
->name
, quoted
? "'()'" : "()");
543 printf ("%s=%s\n", var
->name
, vstr
);
548 /***********************************************************************/
550 /* Utility functions to manage arrays and their contents for expansion */
552 /***********************************************************************/
554 /* Return 1 if NAME is a properly-formed array reference v[sub]. */
556 valid_array_reference (name
)
562 t
= xstrchr (name
, '['); /* ] */
566 r
= legal_identifier (name
);
570 /* Check for a properly-terminated non-blank subscript. */
571 len
= skipsubscript (t
, 0);
572 if (t
[len
] != ']' || len
== 1)
574 for (r
= 1; r
< len
; r
++)
575 if (whitespace (t
[r
]) == 0)
582 /* Expand the array index beginning at S and extending LEN characters. */
584 array_expand_index (s
, len
)
592 exp
= (char *)xmalloc (len
);
593 strncpy (exp
, s
, len
- 1);
596 t
= expand_string_to_string (exp
, 0);
598 t
= expand_string_to_string (exp
, Q_DOUBLE_QUOTES
);
600 this_command_name
= (char *)NULL
;
601 val
= evalexp (t
, &expok
);
606 last_command_exit_value
= EXECUTION_FAILURE
;
607 jump_to_top_level (DISCARD
);
612 /* Return the name of the variable specified by S without any subscript.
613 If SUBP is non-null, return a pointer to the start of the subscript
614 in *SUBP. If LENP is non-null, the length of the subscript is returned
615 in *LENP. This returns newly-allocated memory. */
617 array_variable_name (s
, subp
, lenp
)
624 t
= xstrchr (s
, '[');
631 return ((char *)NULL
);
634 ni
= skipsubscript (s
, ind
);
635 if (ni
<= ind
+ 1 || s
[ni
] != ']')
642 return ((char *)NULL
);
646 ret
= savestring (s
);
657 /* Return the variable specified by S without any subscript. If SUBP is
658 non-null, return a pointer to the start of the subscript in *SUBP.
659 If LENP is non-null, the length of the subscript is returned in *LENP. */
661 array_variable_part (s
, subp
, lenp
)
668 t
= array_variable_name (s
, subp
, lenp
);
670 return ((SHELL_VAR
*)NULL
);
671 var
= find_variable (t
);
674 return (var
== 0 || invisible_p (var
)) ? (SHELL_VAR
*)0 : var
;
677 /* Return a string containing the elements in the array and subscript
678 described by S. If the subscript is * or @, obeys quoting rules akin
679 to the expansion of $* and $@ including double quoting. If RTYPE
680 is non-null it gets 1 if the array reference is name[@] or name[*]
683 array_value_internal (s
, quoted
, allow_all
, rtype
)
685 int quoted
, allow_all
, *rtype
;
689 char *retval
, *t
, *temp
;
693 var
= array_variable_part (s
, &t
, &len
);
695 /* Expand the index, even if the variable doesn't exist, in case side
696 effects are needed, like ${w[i++]} where w is unset. */
703 return ((char *)NULL
); /* error message already printed */
706 if (ALL_ELEMENT_SUB (t
[0]) && t
[1] == ']')
713 return ((char *)NULL
);
715 else if (var
== 0 || value_cell (var
) == 0)
716 return ((char *)NULL
);
717 else if (array_p (var
) == 0)
718 l
= add_string_to_list (value_cell (var
), (WORD_LIST
*)NULL
);
721 l
= array_to_word_list (array_cell (var
));
722 if (l
== (WORD_LIST
*)NULL
)
723 return ((char *) NULL
);
726 if (t
[0] == '*' && (quoted
& (Q_HERE_DOCUMENT
|Q_DOUBLE_QUOTES
)))
728 temp
= string_list_dollar_star (l
);
729 retval
= quote_string (temp
);
732 else /* ${name[@]} or unquoted ${name[*]} */
733 retval
= string_list_dollar_at (l
, quoted
);
741 ind
= array_expand_index (t
, len
);
745 err_badarraysub (var
->name
);
752 return ((char *)NULL
);
755 return ((char *)NULL
);
756 if (array_p (var
) == 0)
757 return (ind
== 0 ? value_cell (var
) : (char *)NULL
);
758 retval
= array_reference (array_cell (var
), ind
);
764 /* Return a string containing the elements described by the array and
765 subscript contained in S, obeying quoting for subscripts * and @. */
767 array_value (s
, quoted
, rtype
)
771 return (array_value_internal (s
, quoted
, 1, rtype
));
774 /* Return the value of the array indexing expression S as a single string.
775 If ALLOW_ALL is 0, do not allow `@' and `*' subscripts. This is used
776 by other parts of the shell such as the arithmetic expression evaluator
779 get_array_value (s
, allow_all
, rtype
)
781 int allow_all
, *rtype
;
783 return (array_value_internal (s
, 0, allow_all
, rtype
));
787 array_keys (s
, quoted
)
792 char *retval
, *t
, *temp
;
796 var
= array_variable_part (s
, &t
, &len
);
799 if (var
== 0 || ALL_ELEMENT_SUB (t
[0]) == 0 || t
[1] != ']')
802 if (array_p (var
) == 0)
803 l
= add_string_to_list ("0", (WORD_LIST
*)NULL
);
806 l
= array_keys_to_word_list (array_cell (var
));
807 if (l
== (WORD_LIST
*)NULL
)
808 return ((char *) NULL
);
811 if (t
[0] == '*' && (quoted
& (Q_HERE_DOCUMENT
|Q_DOUBLE_QUOTES
)))
813 temp
= string_list_dollar_star (l
);
814 retval
= quote_string (temp
);
817 else /* ${!name[@]} or unquoted ${!name[*]} */
818 retval
= string_list_dollar_at (l
, quoted
);
823 #endif /* ARRAY_VARS */