commit bash-20080626 snapshot

This commit is contained in:
Chet Ramey
2011-12-07 09:25:06 -05:00
parent e33f22038c
commit fdf670eaa1
48 changed files with 4104 additions and 1876 deletions
+99
View File
@@ -16068,3 +16068,102 @@ variables.h
- include assoc.h for associative arrays
- defines for case-modifying expansions and associative array variables
- sh_var_assign_func_t functions now take an extra char * parameter
6/25
----
variables.c
- change declarations and definitions of sh_var_assign_func_t functions
to add the extra char * parameter: null_assign, null_array_assign,
assign_seconds, assign_random, assign_lineno, assign_subshell,
assign_dirstack
- change calls to var->assign_func to add extra char * argument
- broke part of body of dispose_variable out into a new function,
dispose_variable_value, which knows how to free all kinds of shell
variable data
- changes to deal with variables with the internal `nofree' attribute
arrayfunc.c
- change calls to var->assign_func to add extra char * argument
- bind_array_var_internal now takes an extra `char *key' argument
- additions for associative array implementation; from bash-4.0-devel
tree
arrayfunc.[ch],subst.c
- expand_compound_array_assignment now takes the variable as the first
argument (SHELL_VAR *); changed function definition and callers
builtins/set.def
- changes to handle associative arrays in `unset'
{execute_cmd,command}.h
- definitions for coproc implementation; from bash-4.0-devel tree
variables.c
- new functions for associative arrays: make_new_assoc_variable,
make_local_assoc_variable
6/26
----
variables.c
- more infrastructure for associative arrays; from bash-4.0-devel tree
- infrastructure for handling assignments to variables with
case-modifying attributes; from bash-4.0-devel tree
config.h.in
- add #defines controlling case-modifying variable attributes and word
expansions
configure.in
- add enable options for case-modifying variable attributes and word
expansions (--enable-casemod-attributes and --enable-casemod-expansions,
respectively); from bash-4.0-devel tree
execute_cmd.c
- add code to fix_assignment_words to handle assignment statements to
"assignment builtins" that seem to be associative arrays. Imperfect
subst.c
- array_remove_pattern now takes a SHELL_VAR * as its first argument
instead of an ARRAY *; from the bash-4.0-devel tree
- changes to array_length_reference for associative arrays; from the
bash-4.0-devel tree
- changes to get_var_and_type for associative arrays; from the
bash-4.0-devel tree
- changes to parameter_brace_substring for associative arrays; from the
bash-4.0-devel tree
- changes to param_expand for associative arrays; from the
bash-4.0-devel tree
builtins/declare.def
- changes for associative arrays: new `-A' option, changes to make
local and global associative array variables; from the bash-4.0-devel
tree
6/27
----
execute_cmd.c
- in execute_command_internal, when short-circuiting execution
because `breaking' or `continuing' is non-zero, preserve the exit
status by returning `last_command_exit_value' instead of an
unconditional EXECUTION_SUCCESS. Fixes bug reported by Roman
Rakus <rrakus@redhat.com>
6/28
----
variables.c
- fix get_var_and_type to appropriately handle references like
${varname[0]}, where `varname' is a scalar variable
make_cmd.[ch],parse.y
- make_here_document now takes a second argument: the current line
number; changed caller (gather_here_documents)
builtins/setattr.def
- added support for associative arrays and the `-A' variable attribute
option; from the bash-4.0-devel tree
subst.c
- change code that transforms `declare -A xxx=(yyy)' to perform the
internal `declare -A xxx' before doing the variable assignment,
because associative arrays have to be declared before being assigned
to as such; uses new function make_internal_declare
+100
View File
@@ -16061,3 +16061,103 @@ subst.c
- change list_remove_pattern, pos_params, pos_params_pat_subst to
call string_list_pos_params. Fixes problems reported by
Stephane Chazelas <stephane_chazelas@yahoo.fr>
6/22
----
variables.h
- include assoc.h for associative arrays
- defines for case-modifying expansions and associative array variables
- sh_var_assign_func_t functions now take an extra char * parameter
6/25
----
variables.c
- change declarations and definitions of sh_var_assign_func_t functions
to add the extra char * parameter: null_assign, null_array_assign,
assign_seconds, assign_random, assign_lineno, assign_subshell,
assign_dirstack
- change calls to var->assign_func to add extra char * argument
- broke part of body of dispose_variable out into a new function,
dispose_variable_value, which knows how to free all kinds of shell
variable data
- changes to deal with variables with the internal `nofree' attribute
arrayfunc.c
- change calls to var->assign_func to add extra char * argument
- bind_array_var_internal now takes an extra `char *key' argument
- additions for associative array implementation; from bash-4.0-devel
tree
arrayfunc.[ch],subst.c
- expand_compound_array_assignment now takes the variable as the first
argument (SHELL_VAR *); changed function definition and callers
builtins/set.def
- changes to handle associative arrays in `unset'
{execute_cmd,command}.h
- definitions for coproc implementation; from bash-4.0-devel tree
variables.c
- new functions for associative arrays: make_new_assoc_variable,
make_local_assoc_variable
6/26
----
variables.c
- more infrastructure for associative arrays; from bash-4.0-devel tree
- infrastructure for handling assignments to variables with
case-modifying attributes; from bash-4.0-devel tree
config.h.in
- add #defines controlling case-modifying variable attributes and word
expansions
configure.in
- add enable options for case-modifying variable attributes and word
expansions (--enable-casemod-attributes and --enable-casemod-expansions,
respectively); from bash-4.0-devel tree
execute_cmd.c
- add code to fix_assignment_words to handle assignment statements to
"assignment builtins" that seem to be associative arrays. Imperfect
subst.c
- array_remove_pattern now takes a SHELL_VAR * as its first argument
instead of an ARRAY *; from the bash-4.0-devel tree
- changes to array_length_reference for associative arrays; from the
bash-4.0-devel tree
- changes to get_var_and_type for associative arrays; from the
bash-4.0-devel tree
- changes to parameter_brace_substring for associative arrays; from the
bash-4.0-devel tree
- changes to param_expand for associative arrays; from the
bash-4.0-devel tree
builtins/declare.def
- changes for associative arrays: new `-A' option, changes to make
local and global associative array variables; from the bash-4.0-devel
tree
6/27
----
execute_cmd.c
- in execute_command_internal, when short-circuiting execution
because `breaking' or `continuing' is non-zero, preserve the exit
status by returning `last_command_exit_value' instead of an
unconditional EXECUTION_SUCCESS. Fixes bug reported by Roman
Rakus <rrakus@redhat.com>
6/28
----
variables.c
- fix get_var_and_type to appropriately handle references like
${varname[0]}, where `varname' is a scalar variable
make_cmd.[ch],parse.y
- make_here_document now takes a second argument: the current line
number; changed caller (gather_here_documents)
builtins/setattr.def
- added support for associative arrays and the `-A' variable attribute
option; from the bash-4.0-devel tree
+6
View File
@@ -745,8 +745,13 @@ tests/array3.sub f
tests/array4.sub f
tests/array5.sub f
tests/array6.sub f
tests/array7.sub f
tests/array-at-star f
tests/array2.right f
tests/assoc.tests f
tests/assoc.right f
tests/assoc1.sub f
tests/assoc2.sub f
tests/braces.tests f
tests/braces.right f
tests/builtins.tests f
@@ -924,6 +929,7 @@ tests/run-arith-for f
tests/run-arith f
tests/run-array f
tests/run-array2 f
tests/run-assoc f
tests/run-braces f
tests/run-builtins f
tests/run-case f
+2
View File
@@ -745,6 +745,7 @@ tests/array3.sub f
tests/array4.sub f
tests/array5.sub f
tests/array6.sub f
tests/array7.sub f
tests/array-at-star f
tests/array2.right f
tests/braces.tests f
@@ -765,6 +766,7 @@ tests/comsub.tests f
tests/comsub.right f
tests/comsub-posix.tests f
tests/comsub-posix.right f
tests/comsub-posix1.sub f
tests/cond.tests f
tests/cond.right f
tests/cond-regexp.sub f
+255 -68
View File
@@ -1,6 +1,6 @@
/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
/* Copyright (C) 2001-2006 Free Software Foundation, Inc.
/* Copyright (C) 2001-2008 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -39,7 +39,7 @@ extern char *this_command_name;
extern int last_command_exit_value;
extern int array_needs_making;
static SHELL_VAR *bind_array_var_internal __P((SHELL_VAR *, arrayind_t, char *, int));
static SHELL_VAR *bind_array_var_internal __P((SHELL_VAR *, arrayind_t, char *, char *, int));
static char *quote_assign __P((const char *));
static void quote_array_assignment_chars __P((WORD_LIST *));
@@ -85,10 +85,42 @@ convert_var_to_array (var)
return var;
}
/* Convert a shell variable to an array variable. The original value is
saved as array[0]. */
SHELL_VAR *
convert_var_to_assoc (var)
SHELL_VAR *var;
{
char *oldval;
HASH_TABLE *hash;
oldval = value_cell (var);
hash = assoc_create (0);
if (oldval)
assoc_insert (hash, "0", oldval);
FREE (value_cell (var));
var_setassoc (var, hash);
/* these aren't valid anymore */
var->dynamic_value = (sh_var_value_func_t *)NULL;
var->assign_func = (sh_var_assign_func_t *)NULL;
INVALIDATE_EXPORTSTR (var);
if (exported_p (var))
array_needs_making++;
VSETATTR (var, att_assoc);
VUNSETATTR (var, att_invisible);
return var;
}
static SHELL_VAR *
bind_array_var_internal (entry, ind, value, flags)
bind_array_var_internal (entry, ind, key, value, flags)
SHELL_VAR *entry;
arrayind_t ind;
char *key;
char *value;
int flags;
{
@@ -101,7 +133,10 @@ bind_array_var_internal (entry, ind, value, flags)
{
dentry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
dentry->name = savestring (entry->name);
newval = array_reference (array_cell (entry), ind);
if (assoc_p (entry))
newval = assoc_reference (assoc_cell (entry), key);
else
newval = array_reference (array_cell (entry), ind);
if (newval)
dentry->value = savestring (newval);
else
@@ -110,7 +145,7 @@ bind_array_var_internal (entry, ind, value, flags)
dentry->value[0] = '\0';
}
dentry->exportstr = 0;
dentry->attributes = entry->attributes & ~(att_array|att_exported);
dentry->attributes = entry->attributes & ~(att_array|att_assoc|att_exported);
/* Leave the rest of the members uninitialized; the code doesn't look
at them. */
newval = make_variable_value (dentry, value, flags);
@@ -120,7 +155,9 @@ bind_array_var_internal (entry, ind, value, flags)
newval = make_variable_value (entry, value, flags);
if (entry->assign_func)
(*entry->assign_func) (entry, newval, ind);
(*entry->assign_func) (entry, newval, ind, key);
else if (assoc_p (entry))
assoc_insert (assoc_cell (entry), key, newval);
else
array_insert (array_cell (entry), ind, newval);
FREE (newval);
@@ -158,7 +195,7 @@ bind_array_variable (name, ind, value, flags)
entry = convert_var_to_array (entry);
/* ENTRY is an array variable, and ARRAY points to the value. */
return (bind_array_var_internal (entry, ind, value, flags));
return (bind_array_var_internal (entry, ind, 0, value, flags));
}
SHELL_VAR *
@@ -168,9 +205,30 @@ bind_array_element (entry, ind, value, flags)
char *value;
int flags;
{
return (bind_array_var_internal (entry, ind, value, flags));
return (bind_array_var_internal (entry, ind, 0, value, flags));
}
SHELL_VAR *
bind_assoc_variable (entry, name, key, value, flags)
SHELL_VAR *entry;
char *name;
char *key;
char *value;
int flags;
{
SHELL_VAR *dentry;
char *newval;
if (readonly_p (entry) || noassign_p (entry))
{
if (readonly_p (entry))
err_readonly (name);
return (entry);
}
return (bind_array_var_internal (entry, 0, key, value, flags));
}
/* Parse NAME, a lhs of an assignment statement of the form v[s], and
assign VALUE to that array element by calling bind_array_variable(). */
SHELL_VAR *
@@ -178,7 +236,7 @@ assign_array_element (name, value, flags)
char *name, *value;
int flags;
{
char *sub, *vname;
char *sub, *vname, *akey;
arrayind_t ind;
int sublen;
SHELL_VAR *entry;
@@ -195,15 +253,32 @@ assign_array_element (name, value, flags)
return ((SHELL_VAR *)NULL);
}
ind = array_expand_index (sub, sublen);
if (ind < 0)
{
free (vname);
err_badarraysub (name);
return ((SHELL_VAR *)NULL);
}
entry = find_variable (vname);
entry = bind_array_variable (vname, ind, value, flags);
if (entry && assoc_p (entry))
{
sub[sublen-1] = '\0';
akey = expand_assignment_string_to_string (sub, 0); /* [ */
sub[sublen-1] = ']';
if (akey == 0 || *akey == 0)
{
free (vname);
err_badarraysub (name);
return ((SHELL_VAR *)NULL);
}
entry = bind_assoc_variable (entry, vname, akey, value, flags);
}
else
{
ind = array_expand_index (sub, sublen);
if (ind < 0)
{
free (vname);
err_badarraysub (name);
return ((SHELL_VAR *)NULL);
}
entry = bind_array_variable (vname, ind, value, flags);
}
free (vname);
return (entry);
@@ -211,27 +286,33 @@ assign_array_element (name, value, flags)
/* Find the array variable corresponding to NAME. If there is no variable,
create a new array variable. If the variable exists but is not an array,
convert it to an indexed array. If CHECK_FLAGS is non-zero, an existing
convert it to an indexed array. If FLAGS&1 is non-zero, an existing
variable is checked for the readonly or noassign attribute in preparation
for assignment (e.g., by the `read' builtin). */
for assignment (e.g., by the `read' builtin). If FLAGS&2 is non-zero, we
create an associative array. */
SHELL_VAR *
find_or_make_array_variable (name, check_flags)
find_or_make_array_variable (name, flags)
char *name;
int check_flags;
int flags;
{
SHELL_VAR *var;
var = find_variable (name);
if (var == 0)
var = make_new_array_variable (name);
else if (check_flags && (readonly_p (var) || noassign_p (var)))
var = (flags & 2) ? make_new_assoc_variable (name) : make_new_array_variable (name);
else if ((flags & 1) && (readonly_p (var) || noassign_p (var)))
{
if (readonly_p (var))
err_readonly (name);
return ((SHELL_VAR *)NULL);
}
else if (array_p (var) == 0)
else if ((flags & 2) && array_p (var))
{
report_error (_("%s: cannot convert indexed to associative array"), name);
return ((SHELL_VAR *)NULL);
}
else if (array_p (var) == 0 && assoc_p (var) == 0)
var = convert_var_to_array (var);
return (var);
@@ -245,8 +326,13 @@ assign_array_from_string (name, value, flags)
int flags;
{
SHELL_VAR *var;
int vflags;
var = find_or_make_array_variable (name, 1);
vflags = 1;
if (flags & ASS_MKASSOC)
vflags |= 2;
var = find_or_make_array_variable (name, vflags);
if (var == 0)
return ((SHELL_VAR *)NULL);
@@ -270,14 +356,15 @@ assign_array_var_from_word_list (var, list, flags)
for (l = list; l; l = l->next, i++)
if (var->assign_func)
(*var->assign_func) (var, l->word->word, i);
(*var->assign_func) (var, l->word->word, i, 0);
else
array_insert (a, i, l->word->word);
return var;
}
WORD_LIST *
expand_compound_array_assignment (value, flags)
expand_compound_array_assignment (var, value, flags)
SHELL_VAR *var;
char *value;
int flags;
{
@@ -326,18 +413,30 @@ assign_compound_array_list (var, nlist, flags)
int flags;
{
ARRAY *a;
HASH_TABLE *h;
WORD_LIST *list;
char *w, *val, *nval;
int len, iflags;
arrayind_t ind, last_ind;
char *akey;
a = array_cell (var);
a = (var && array_p (var)) ? array_cell (var) : (ARRAY *)0;
h = (var && assoc_p (var)) ? assoc_cell (var) : (HASH_TABLE *)0;
akey = (char *)0;
ind = 0;
/* Now that we are ready to assign values to the array, kill the existing
value. */
if (a && (flags & ASS_APPEND) == 0)
array_flush (a);
last_ind = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
if ((flags & ASS_APPEND) == 0)
{
if (array_p (var) && a)
array_flush (a);
else if (assoc_p (var) && h)
assoc_flush (h);
}
last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0;
for (list = nlist; list; list = list->next)
{
@@ -352,9 +451,14 @@ assign_compound_array_list (var, nlist, flags)
/* XXX - changes for `+=' */
if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
{
if (assoc_p (var))
{
err_badarraysub (w);
continue;
}
nval = make_variable_value (var, w, flags);
if (var->assign_func)
(*var->assign_func) (var, nval, last_ind);
(*var->assign_func) (var, nval, last_ind, 0);
else
array_insert (a, last_ind, nval);
FREE (nval);
@@ -370,17 +474,34 @@ assign_compound_array_list (var, nlist, flags)
if (ALL_ELEMENT_SUB (w[1]) && len == 2)
{
report_error (_("%s: cannot assign to non-numeric index"), w);
if (assoc_p (var))
report_error (_("%s: invalid associative array key"), w);
else
report_error (_("%s: cannot assign to non-numeric index"), w);
continue;
}
ind = array_expand_index (w + 1, len);
if (ind < 0)
if (array_p (var))
{
err_badarraysub (w);
continue;
ind = array_expand_index (w + 1, len);
if (ind < 0)
{
err_badarraysub (w);
continue;
}
last_ind = ind;
}
last_ind = ind;
else if (assoc_p (var))
{
akey = substring (w, 1, len);
if (akey == 0 || *akey == 0)
{
err_badarraysub (w);
continue;
}
}
/* XXX - changes for `+=' -- just accept the syntax. ksh93 doesn't do this */
if (w[len + 1] == '+' && w[len + 2] == '=')
{
@@ -390,6 +511,11 @@ assign_compound_array_list (var, nlist, flags)
else
val = w + len + 2;
}
else if (assoc_p (var))
{
report_error (_("%s: %s: must use subscript when assigning associative array"), var->name, w);
continue;
}
else /* No [ind]=value, just a stray `=' */
{
ind = last_ind;
@@ -398,7 +524,7 @@ assign_compound_array_list (var, nlist, flags)
if (integer_p (var))
this_command_name = (char *)NULL; /* no command name for errors */
bind_array_var_internal (var, ind, val, iflags);
bind_array_var_internal (var, ind, akey, val, iflags);
last_ind++;
}
}
@@ -416,7 +542,7 @@ assign_array_var_from_string (var, value, flags)
if (value == 0)
return var;
nlist = expand_compound_array_assignment (value, flags);
nlist = expand_compound_array_assignment (var, value, flags);
assign_compound_array_list (var, nlist, flags);
if (nlist)
@@ -424,6 +550,9 @@ assign_array_var_from_string (var, value, flags)
return (var);
}
/* Quote globbing chars and characters in $IFS before the `=' in an assignment
statement (usually a compound array assignment) to protect them from
unwanted filename expansion or word splitting. */
static char *
quote_assign (string)
const char *string;
@@ -453,8 +582,7 @@ quote_assign (string)
}
/* For each word in a compound array assignment, if the word looks like
[ind]=value, quote the `[' and `]' before the `=' to protect them from
unwanted filename expansion. */
[ind]=value, quote globbing chars and characters in $IFS before the `='. */
static void
quote_array_assignment_chars (list)
WORD_LIST *list;
@@ -524,7 +652,7 @@ skipsubscript (s, i)
c = s[i];
if (c == 0)
break;
break;
else if (c == '[')
count++;
else if (c == ']')
@@ -544,6 +672,7 @@ unbind_array_element (var, sub)
{
int len;
arrayind_t ind;
char *akey;
ARRAY_ELEMENT *ae;
len = skipsubscript (sub, 0);
@@ -559,15 +688,30 @@ unbind_array_element (var, sub)
unbind_variable (var->name);
return (0);
}
ind = array_expand_index (sub, len+1);
if (ind < 0)
if (assoc_p (var))
{
builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
return -1;
akey = expand_assignment_string_to_string (sub, 0); /* [ */
if (akey == 0 || *akey == 0)
{
builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
return -1;
}
assoc_remove (assoc_cell (var), akey);
}
ae = array_remove (array_cell (var), ind);
if (ae)
array_dispose_element (ae);
else
{
ind = array_expand_index (sub, len+1);
if (ind < 0)
{
builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
return -1;
}
ae = array_remove (array_cell (var), ind);
if (ae)
array_dispose_element (ae);
}
return 0;
}
@@ -591,6 +735,26 @@ print_array_assignment (var, quoted)
}
}
/* Format and output an associative array assignment in compound form
VAR=(VALUES), suitable for re-use as input. */
void
print_assoc_assignment (var, quoted)
SHELL_VAR *var;
int quoted;
{
char *vstr;
vstr = assoc_to_assign (assoc_cell (var), quoted);
if (vstr == 0)
printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
else
{
printf ("%s=%s\n", var->name, vstr);
free (vstr);
}
}
/***********************************************************************/
/* */
/* Utility functions to manage arrays and their contents for expansion */
@@ -730,6 +894,7 @@ array_value_internal (s, quoted, allow_all, rtype)
{
int len;
arrayind_t ind;
char *akey;
char *retval, *t, *temp;
WORD_LIST *l;
SHELL_VAR *var;
@@ -758,8 +923,14 @@ array_value_internal (s, quoted, allow_all, rtype)
}
else if (var == 0 || value_cell (var) == 0)
return ((char *)NULL);
else if (array_p (var) == 0)
else if (array_p (var) == 0 && assoc_p (var) == 0)
l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
else if (assoc_p (var))
{
l = assoc_to_word_list (assoc_cell (var));
if (l == (WORD_LIST *)NULL)
return ((char *)NULL);
}
else
{
l = array_to_word_list (array_cell (var));
@@ -782,24 +953,40 @@ array_value_internal (s, quoted, allow_all, rtype)
{
if (rtype)
*rtype = 0;
ind = array_expand_index (t, len);
if (ind < 0)
if (var == 0 || array_p (var) || assoc_p (var) == 0)
{
if (var)
err_badarraysub (var->name);
else
ind = array_expand_index (t, len);
if (ind < 0)
{
t[-1] = '\0';
err_badarraysub (s);
t[-1] = '['; /* ] */
index_error:
if (var)
err_badarraysub (var->name);
else
{
t[-1] = '\0';
err_badarraysub (s);
t[-1] = '['; /* ] */
}
return ((char *)NULL);
}
return ((char *)NULL);
}
else if (assoc_p (var))
{
t[len - 1] = '\0';
akey = expand_assignment_string_to_string (t, 0); /* [ */
t[len - 1] = ']';
if (akey == 0 || *akey == 0)
goto index_error;
}
if (var == 0)
return ((char *)NULL);
if (array_p (var) == 0)
if (array_p (var) == 0 && assoc_p (var) == 0)
return (ind == 0 ? value_cell (var) : (char *)NULL);
retval = array_reference (array_cell (var), ind);
else if (assoc_p (var))
retval = assoc_reference (assoc_cell (var), akey);
else
retval = array_reference (array_cell (var), ind);
}
return retval;
@@ -843,14 +1030,14 @@ array_keys (s, quoted)
if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']')
return (char *)NULL;
if (array_p (var) == 0)
if (array_p (var) == 0 && assoc_p (var) == 0)
l = add_string_to_list ("0", (WORD_LIST *)NULL);
else if (assoc_p (var))
l = assoc_keys_to_word_list (assoc_cell (var));
else
{
l = array_keys_to_word_list (array_cell (var));
if (l == (WORD_LIST *)NULL)
return ((char *) NULL);
}
l = array_keys_to_word_list (array_cell (var));
if (l == (WORD_LIST *)NULL)
return ((char *) NULL);
if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
{
+291 -81
View File
@@ -1,6 +1,6 @@
/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
/* Copyright (C) 2001-2006 Free Software Foundation, Inc.
/* Copyright (C) 2001-2008 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -39,8 +39,9 @@ extern char *this_command_name;
extern int last_command_exit_value;
extern int array_needs_making;
static SHELL_VAR *bind_array_var_internal __P((SHELL_VAR *, arrayind_t, char *, int));
static SHELL_VAR *bind_array_var_internal __P((SHELL_VAR *, arrayind_t, char *, char *, int));
static char *quote_assign __P((const char *));
static void quote_array_assignment_chars __P((WORD_LIST *));
static char *array_value_internal __P((char *, int, int, int *));
@@ -84,10 +85,42 @@ convert_var_to_array (var)
return var;
}
/* Convert a shell variable to an array variable. The original value is
saved as array[0]. */
SHELL_VAR *
convert_var_to_assoc (var)
SHELL_VAR *var;
{
char *oldval;
HASH_TABLE *hash;
oldval = value_cell (var);
hash = assoc_create (0);
if (oldval)
assoc_insert (hash, "0", oldval);
FREE (value_cell (var));
var_setassoc (var, hash);
/* these aren't valid anymore */
var->dynamic_value = (sh_var_value_func_t *)NULL;
var->assign_func = (sh_var_assign_func_t *)NULL;
INVALIDATE_EXPORTSTR (var);
if (exported_p (var))
array_needs_making++;
VSETATTR (var, att_assoc);
VUNSETATTR (var, att_invisible);
return var;
}
static SHELL_VAR *
bind_array_var_internal (entry, ind, value, flags)
bind_array_var_internal (entry, ind, key, value, flags)
SHELL_VAR *entry;
arrayind_t ind;
char *key;
char *value;
int flags;
{
@@ -100,7 +133,10 @@ bind_array_var_internal (entry, ind, value, flags)
{
dentry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
dentry->name = savestring (entry->name);
newval = array_reference (array_cell (entry), ind);
if (assoc_p (entry))
newval = assoc_reference (assoc_cell (entry), key);
else
newval = array_reference (array_cell (entry), ind);
if (newval)
dentry->value = savestring (newval);
else
@@ -109,7 +145,7 @@ bind_array_var_internal (entry, ind, value, flags)
dentry->value[0] = '\0';
}
dentry->exportstr = 0;
dentry->attributes = entry->attributes & ~(att_array|att_exported);
dentry->attributes = entry->attributes & ~(att_array|att_assoc|att_exported);
/* Leave the rest of the members uninitialized; the code doesn't look
at them. */
newval = make_variable_value (dentry, value, flags);
@@ -119,7 +155,9 @@ bind_array_var_internal (entry, ind, value, flags)
newval = make_variable_value (entry, value, flags);
if (entry->assign_func)
(*entry->assign_func) (entry, newval, ind);
(*entry->assign_func) (entry, newval, ind, key);
else if (assoc_p (entry))
assoc_insert (assoc_cell (entry), key, newval);
else
array_insert (array_cell (entry), ind, newval);
FREE (newval);
@@ -157,7 +195,7 @@ bind_array_variable (name, ind, value, flags)
entry = convert_var_to_array (entry);
/* ENTRY is an array variable, and ARRAY points to the value. */
return (bind_array_var_internal (entry, ind, value, flags));
return (bind_array_var_internal (entry, ind, 0, value, flags));
}
SHELL_VAR *
@@ -167,9 +205,30 @@ bind_array_element (entry, ind, value, flags)
char *value;
int flags;
{
return (bind_array_var_internal (entry, ind, value, flags));
return (bind_array_var_internal (entry, ind, 0, value, flags));
}
SHELL_VAR *
bind_assoc_variable (entry, name, key, value, flags)
SHELL_VAR *entry;
char *name;
char *key;
char *value;
int flags;
{
SHELL_VAR *dentry;
char *newval;
if (readonly_p (entry) || noassign_p (entry))
{
if (readonly_p (entry))
err_readonly (name);
return (entry);
}
return (bind_array_var_internal (entry, 0, key, value, flags));
}
/* Parse NAME, a lhs of an assignment statement of the form v[s], and
assign VALUE to that array element by calling bind_array_variable(). */
SHELL_VAR *
@@ -177,7 +236,7 @@ assign_array_element (name, value, flags)
char *name, *value;
int flags;
{
char *sub, *vname;
char *sub, *vname, *akey;
arrayind_t ind;
int sublen;
SHELL_VAR *entry;
@@ -194,15 +253,32 @@ assign_array_element (name, value, flags)
return ((SHELL_VAR *)NULL);
}
ind = array_expand_index (sub, sublen);
if (ind < 0)
{
free (vname);
err_badarraysub (name);
return ((SHELL_VAR *)NULL);
}
entry = find_variable (vname);
entry = bind_array_variable (vname, ind, value, flags);
if (entry && assoc_p (entry))
{
sub[sublen-1] = '\0';
akey = expand_assignment_string_to_string (sub, 0); /* [ */
sub[sublen-1] = ']';
if (akey == 0 || *akey == 0)
{
free (vname);
err_badarraysub (name);
return ((SHELL_VAR *)NULL);
}
entry = bind_assoc_variable (entry, vname, akey, value, flags);
}
else
{
ind = array_expand_index (sub, sublen);
if (ind < 0)
{
free (vname);
err_badarraysub (name);
return ((SHELL_VAR *)NULL);
}
entry = bind_array_variable (vname, ind, value, flags);
}
free (vname);
return (entry);
@@ -210,27 +286,33 @@ assign_array_element (name, value, flags)
/* Find the array variable corresponding to NAME. If there is no variable,
create a new array variable. If the variable exists but is not an array,
convert it to an indexed array. If CHECK_FLAGS is non-zero, an existing
convert it to an indexed array. If FLAGS&1 is non-zero, an existing
variable is checked for the readonly or noassign attribute in preparation
for assignment (e.g., by the `read' builtin). */
for assignment (e.g., by the `read' builtin). If FLAGS&2 is non-zero, we
create an associative array. */
SHELL_VAR *
find_or_make_array_variable (name, check_flags)
find_or_make_array_variable (name, flags)
char *name;
int check_flags;
int flags;
{
SHELL_VAR *var;
var = find_variable (name);
if (var == 0)
var = make_new_array_variable (name);
else if (check_flags && (readonly_p (var) || noassign_p (var)))
var = (flags & 2) ? make_new_assoc_variable (name) : make_new_array_variable (name);
else if ((flags & 1) && (readonly_p (var) || noassign_p (var)))
{
if (readonly_p (var))
err_readonly (name);
return ((SHELL_VAR *)NULL);
}
else if (array_p (var) == 0)
else if ((flags & 2) && array_p (var))
{
report_error (_("%s: cannot convert indexed to associative array"), name);
return ((SHELL_VAR *)NULL);
}
else if (array_p (var) == 0 && assoc_p (var) == 0)
var = convert_var_to_array (var);
return (var);
@@ -244,8 +326,13 @@ assign_array_from_string (name, value, flags)
int flags;
{
SHELL_VAR *var;
int vflags;
var = find_or_make_array_variable (name, 1);
vflags = 1;
if (flags & ASS_MKASSOC)
vflags |= 2;
var = find_or_make_array_variable (name, vflags);
if (var == 0)
return ((SHELL_VAR *)NULL);
@@ -269,14 +356,15 @@ assign_array_var_from_word_list (var, list, flags)
for (l = list; l; l = l->next, i++)
if (var->assign_func)
(*var->assign_func) (var, l->word->word, i);
(*var->assign_func) (var, l->word->word, i, 0);
else
array_insert (a, i, l->word->word);
return var;
}
WORD_LIST *
expand_compound_array_assignment (value, flags)
expand_compound_array_assignment (var, value, flags)
SHELL_VAR *var;
char *value;
int flags;
{
@@ -325,18 +413,35 @@ assign_compound_array_list (var, nlist, flags)
int flags;
{
ARRAY *a;
HASH_TABLE *h;
WORD_LIST *list;
char *w, *val, *nval;
int len, iflags;
arrayind_t ind, last_ind;
char *akey;
a = array_cell (var);
a = (ARRAY *)0;
h = (HASH_TABLE *)0;
if (assoc_p (var))
h = assoc_cell (var);
else
a = array_cell (var);
akey = (char *)0;
ind = 0;
/* Now that we are ready to assign values to the array, kill the existing
value. */
if (a && (flags & ASS_APPEND) == 0)
array_flush (a);
last_ind = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
if ((flags & ASS_APPEND) == 0)
{
if (array_p (var) && a)
array_flush (a);
else if (assoc_p (var) && h)
assoc_flush (h);
}
last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0;
for (list = nlist; list; list = list->next)
{
@@ -351,9 +456,14 @@ assign_compound_array_list (var, nlist, flags)
/* XXX - changes for `+=' */
if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
{
if (assoc_p (var))
{
err_badarraysub (w);
continue;
}
nval = make_variable_value (var, w, flags);
if (var->assign_func)
(*var->assign_func) (var, nval, last_ind);
(*var->assign_func) (var, nval, last_ind, 0);
else
array_insert (a, last_ind, nval);
FREE (nval);
@@ -369,17 +479,34 @@ assign_compound_array_list (var, nlist, flags)
if (ALL_ELEMENT_SUB (w[1]) && len == 2)
{
report_error (_("%s: cannot assign to non-numeric index"), w);
if (assoc_p (var))
report_error (_("%s: invalid associative array key"), w);
else
report_error (_("%s: cannot assign to non-numeric index"), w);
continue;
}
ind = array_expand_index (w + 1, len);
if (ind < 0)
if (array_p (var))
{
err_badarraysub (w);
continue;
ind = array_expand_index (w + 1, len);
if (ind < 0)
{
err_badarraysub (w);
continue;
}
last_ind = ind;
}
last_ind = ind;
else if (assoc_p (var))
{
akey = substring (w, 1, len);
if (akey == 0 || *akey == 0)
{
err_badarraysub (w);
continue;
}
}
/* XXX - changes for `+=' -- just accept the syntax. ksh93 doesn't do this */
if (w[len + 1] == '+' && w[len + 2] == '=')
{
@@ -389,6 +516,11 @@ assign_compound_array_list (var, nlist, flags)
else
val = w + len + 2;
}
else if (assoc_p (var))
{
report_error (_("%s: %s: must use subscript when assigning associative array"), var->name, w);
continue;
}
else /* No [ind]=value, just a stray `=' */
{
ind = last_ind;
@@ -397,7 +529,7 @@ assign_compound_array_list (var, nlist, flags)
if (integer_p (var))
this_command_name = (char *)NULL; /* no command name for errors */
bind_array_var_internal (var, ind, val, iflags);
bind_array_var_internal (var, ind, akey, val, iflags);
last_ind++;
}
}
@@ -415,7 +547,7 @@ assign_array_var_from_string (var, value, flags)
if (value == 0)
return var;
nlist = expand_compound_array_assignment (value, flags);
nlist = expand_compound_array_assignment (var, value, flags);
assign_compound_array_list (var, nlist, flags);
if (nlist)
@@ -423,15 +555,44 @@ assign_array_var_from_string (var, value, flags)
return (var);
}
/* Quote globbing chars and characters in $IFS before the `=' in an assignment
statement (usually a compound array assignment) to protect them from
unwanted filename expansion or word splitting. */
static char *
quote_assign (string)
const char *string;
{
size_t slen;
int saw_eq;
char *temp, *t;
const char *s, *send;
DECLARE_MBSTATE;
slen = strlen (string);
send = string + slen;
t = temp = (char *)xmalloc (slen * 2 + 1);
saw_eq = 0;
for (s = string; *s; )
{
if (*s == '=')
saw_eq = 1;
if (saw_eq == 0 && (glob_char_p (s) || isifs (*s)))
*t++ = '\\';
COPY_CHAR_P (t, s, send);
}
*t = '\0';
return temp;
}
/* For each word in a compound array assignment, if the word looks like
[ind]=value, quote the `[' and `]' before the `=' to protect them from
unwanted filename expansion. */
[ind]=value, quote globbing chars and characters in $IFS before the `='. */
static void
quote_array_assignment_chars (list)
WORD_LIST *list;
{
char *s, *t, *nword;
int saw_eq;
char *nword;
WORD_LIST *l;
for (l = list; l; l = l->next)
@@ -441,17 +602,7 @@ quote_array_assignment_chars (list)
/* Don't bother if it doesn't look like [ind]=value */
if (l->word->word[0] != '[' || xstrchr (l->word->word, '=') == 0) /* ] */
continue;
s = nword = (char *)xmalloc (strlen (l->word->word) * 2 + 1);
saw_eq = 0;
for (t = l->word->word; *t; )
{
if (*t == '=')
saw_eq = 1;
if (saw_eq == 0 && (*t == '[' || *t == ']'))
*s++ = '\\';
*s++ = *t++;
}
*s = '\0';
nword = quote_assign (l->word->word);
free (l->word->word);
l->word->word = nword;
}
@@ -506,7 +657,7 @@ skipsubscript (s, i)
c = s[i];
if (c == 0)
break;
break;
else if (c == '[')
count++;
else if (c == ']')
@@ -526,6 +677,7 @@ unbind_array_element (var, sub)
{
int len;
arrayind_t ind;
char *akey;
ARRAY_ELEMENT *ae;
len = skipsubscript (sub, 0);
@@ -541,15 +693,30 @@ unbind_array_element (var, sub)
unbind_variable (var->name);
return (0);
}
ind = array_expand_index (sub, len+1);
if (ind < 0)
if (assoc_p (var))
{
builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
return -1;
akey = expand_assignment_string_to_string (sub, 0); /* [ */
if (akey == 0 || *akey == 0)
{
builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
return -1;
}
assoc_remove (assoc_cell (var), akey);
}
ae = array_remove (array_cell (var), ind);
if (ae)
array_dispose_element (ae);
else
{
ind = array_expand_index (sub, len+1);
if (ind < 0)
{
builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
return -1;
}
ae = array_remove (array_cell (var), ind);
if (ae)
array_dispose_element (ae);
}
return 0;
}
@@ -573,6 +740,26 @@ print_array_assignment (var, quoted)
}
}
/* Format and output an associative array assignment in compound form
VAR=(VALUES), suitable for re-use as input. */
void
print_assoc_assignment (var, quoted)
SHELL_VAR *var;
int quoted;
{
char *vstr;
vstr = assoc_to_assign (assoc_cell (var), quoted);
if (vstr == 0)
printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
else
{
printf ("%s=%s\n", var->name, vstr);
free (vstr);
}
}
/***********************************************************************/
/* */
/* Utility functions to manage arrays and their contents for expansion */
@@ -712,6 +899,7 @@ array_value_internal (s, quoted, allow_all, rtype)
{
int len;
arrayind_t ind;
char *akey;
char *retval, *t, *temp;
WORD_LIST *l;
SHELL_VAR *var;
@@ -740,8 +928,14 @@ array_value_internal (s, quoted, allow_all, rtype)
}
else if (var == 0 || value_cell (var) == 0)
return ((char *)NULL);
else if (array_p (var) == 0)
else if (array_p (var) == 0 && assoc_p (var) == 0)
l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
else if (assoc_p (var))
{
l = assoc_to_word_list (assoc_cell (var));
if (l == (WORD_LIST *)NULL)
return ((char *)NULL);
}
else
{
l = array_to_word_list (array_cell (var));
@@ -764,24 +958,40 @@ array_value_internal (s, quoted, allow_all, rtype)
{
if (rtype)
*rtype = 0;
ind = array_expand_index (t, len);
if (ind < 0)
if (var == 0 || array_p (var) || assoc_p (var) == 0)
{
if (var)
err_badarraysub (var->name);
else
ind = array_expand_index (t, len);
if (ind < 0)
{
t[-1] = '\0';
err_badarraysub (s);
t[-1] = '['; /* ] */
index_error:
if (var)
err_badarraysub (var->name);
else
{
t[-1] = '\0';
err_badarraysub (s);
t[-1] = '['; /* ] */
}
return ((char *)NULL);
}
return ((char *)NULL);
}
else if (assoc_p (var))
{
t[len - 1] = '\0';
akey = expand_assignment_string_to_string (t, 0); /* [ */
t[len - 1] = ']';
if (akey == 0 || *akey == 0)
goto index_error;
}
if (var == 0)
return ((char *)NULL);
if (array_p (var) == 0)
if (array_p (var) == 0 && assoc_p (var) == 0)
return (ind == 0 ? value_cell (var) : (char *)NULL);
retval = array_reference (array_cell (var), ind);
else if (assoc_p (var))
retval = assoc_reference (assoc_cell (var), akey);
else
retval = array_reference (array_cell (var), ind);
}
return retval;
@@ -825,14 +1035,14 @@ array_keys (s, quoted)
if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']')
return (char *)NULL;
if (array_p (var) == 0)
if (array_p (var) == 0 && assoc_p (var) == 0)
l = add_string_to_list ("0", (WORD_LIST *)NULL);
else if (assoc_p (var))
l = assoc_keys_to_word_list (assoc_cell (var));
else
{
l = array_keys_to_word_list (array_cell (var));
if (l == (WORD_LIST *)NULL)
return ((char *) NULL);
}
l = array_keys_to_word_list (array_cell (var));
if (l == (WORD_LIST *)NULL)
return ((char *) NULL);
if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
{
+5 -2
View File
@@ -1,6 +1,6 @@
/* arrayfunc.h -- declarations for miscellaneous array functions in arrayfunc.c */
/* Copyright (C) 2001-2004 Free Software Foundation, Inc.
/* Copyright (C) 2001-2008 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -26,6 +26,7 @@
#if defined (ARRAY_VARS)
extern SHELL_VAR *convert_var_to_array __P((SHELL_VAR *));
extern SHELL_VAR *convert_var_to_assoc __P((SHELL_VAR *));
extern SHELL_VAR *bind_array_variable __P((char *, arrayind_t, char *, int));
extern SHELL_VAR *bind_array_element __P((SHELL_VAR *, arrayind_t, char *, int));
@@ -36,13 +37,15 @@ extern SHELL_VAR *find_or_make_array_variable __P((char *, int));
extern SHELL_VAR *assign_array_from_string __P((char *, char *, int));
extern SHELL_VAR *assign_array_var_from_word_list __P((SHELL_VAR *, WORD_LIST *, int));
extern WORD_LIST *expand_compound_array_assignment __P((char *, int));
extern WORD_LIST *expand_compound_array_assignment __P((SHELL_VAR *, char *, int));
extern void assign_compound_array_list __P((SHELL_VAR *, WORD_LIST *, int));
extern SHELL_VAR *assign_array_var_from_string __P((SHELL_VAR *, char *, int));
extern int unbind_array_element __P((SHELL_VAR *, char *));
extern int skipsubscript __P((const char *, int));
extern void print_array_assignment __P((SHELL_VAR *, int));
extern void print_assoc_assignment __P((SHELL_VAR *, int));
extern arrayind_t array_expand_index __P((char *, int));
extern int valid_array_reference __P((char *));
+30 -1
View File
@@ -1,5 +1,5 @@
@%:@! /bin/sh
@%:@ From configure.in for Bash 4.0, version 4.001.
@%:@ From configure.in for Bash 4.0, version 4.002.
@%:@ Guess values for system-dependent variables and create Makefiles.
@%:@ Generated by GNU Autoconf 2.61 for bash 4.0-devel.
@%:@
@@ -1365,6 +1365,10 @@ Optional Features:
--enable-bang-history turn on csh-style history substitution
--enable-brace-expansion
include brace expansion
--enable-casemod-attributes
include case-modifying variable attributes
--enable-casemod-expansions
include case-modifying word expansions
--enable-command-timing enable the time reserved word and command timing
--enable-cond-command enable the conditional command
--enable-cond-regexp enable extended regular expression matching in
@@ -2259,6 +2263,8 @@ opt_separate_help=no
opt_multibyte=yes
opt_debugger=yes
opt_single_longdoc_strings=yes
opt_casemod_attrs=yes
opt_casemod_expansions=yes
opt_static_link=no
opt_profiling=no
@@ -2278,6 +2284,7 @@ if test $opt_minimal_config = yes; then
opt_extended_glob=no opt_cond_command=no opt_arith_for_command=no
opt_net_redirs=no opt_progcomp=no opt_separate_help=no
opt_multibyte=yes opt_cond_regexp=no
opt_casemod_attrs=no opt_casemod_expansions=no
fi
# Check whether --enable-alias was given.
@@ -2305,6 +2312,16 @@ if test "${enable_brace_expansion+set}" = set; then
enableval=$enable_brace_expansion; opt_brace_expansion=$enableval
fi
# Check whether --enable-casemod-attributes was given.
if test "${enable_casemod_attributes+set}" = set; then
enableval=$enable_casemod_attributes; opt_casemod_attrs=$enableval
fi
# Check whether --enable-casemod-expansions was given.
if test "${enable_casemod_expansions+set}" = set; then
enableval=$enable_casemod_expansions; opt_casemod_expansions=$enableval
fi
# Check whether --enable-command-timing was given.
if test "${enable_command_timing+set}" = set; then
enableval=$enable_command_timing; opt_command_timing=$enableval
@@ -2575,6 +2592,18 @@ cat >>confdefs.h <<\_ACEOF
@%:@define DEBUGGER 1
_ACEOF
fi
if test $opt_casemod_attrs = yes; then
cat >>confdefs.h <<\_ACEOF
@%:@define CASEMOD_ATTRS 1
_ACEOF
fi
if test $opt_casemod_expansions = yes; then
cat >>confdefs.h <<\_ACEOF
@%:@define CASEMOD_EXPANSIONS 1
_ACEOF
fi
if test $opt_memscramble = yes; then
+8 -8
View File
@@ -15,15 +15,15 @@
'configure.in'
],
{
'_LT_AC_TAGCONFIG' => 1,
'AM_PROG_F77_C_O' => 1,
'AC_INIT' => 1,
'_LT_AC_TAGCONFIG' => 1,
'm4_pattern_forbid' => 1,
'AC_INIT' => 1,
'AC_CANONICAL_TARGET' => 1,
'AC_SUBST' => 1,
'AC_CONFIG_LIBOBJ_DIR' => 1,
'AC_FC_SRCEXT' => 1,
'AC_SUBST' => 1,
'AC_CANONICAL_HOST' => 1,
'AC_FC_SRCEXT' => 1,
'AC_PROG_LIBTOOL' => 1,
'AM_INIT_AUTOMAKE' => 1,
'AC_CONFIG_SUBDIRS' => 1,
@@ -31,8 +31,8 @@
'LT_CONFIG_LTDL_DIR' => 1,
'AC_REQUIRE_AUX_FILE' => 1,
'AC_CONFIG_LINKS' => 1,
'm4_sinclude' => 1,
'LT_SUPPORTED_TAG' => 1,
'm4_sinclude' => 1,
'AM_MAINTAINER_MODE' => 1,
'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
'_m4_warn' => 1,
@@ -49,11 +49,11 @@
'AH_OUTPUT' => 1,
'_AM_SUBST_NOTMAKE' => 1,
'AC_CONFIG_AUX_DIR' => 1,
'sinclude' => 1,
'm4_pattern_allow' => 1,
'AM_PROG_CC_C_O' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'm4_pattern_allow' => 1,
'sinclude' => 1,
'AM_CONDITIONAL' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'AC_CONFIG_HEADERS' => 1,
'AC_DEFINE_TRACE_LITERAL' => 1,
'm4_include' => 1,
+1403 -1393
View File
File diff suppressed because it is too large Load Diff
+54 -16
View File
@@ -36,7 +36,8 @@ Options:
-p display the attributes and value of each NAME
Options which set attributes:
-a to make NAMEs arrays (if supported)
-a to make NAMEs indexed arrays (if supported)
-A to make NAMEs associative arrays (if supported)
-i to make NAMEs have the `integer' attribute
-r to make NAMEs readonly
-t to make NAMEs have the `trace' attribute
@@ -123,7 +124,7 @@ local_builtin (list)
}
#if defined (ARRAY_VARS)
# define DECLARE_OPTS "+afiprtxF"
# define DECLARE_OPTS "+afiprtxAF"
#else
# define DECLARE_OPTS "+fiprtxF"
#endif
@@ -134,7 +135,8 @@ declare_internal (list, local_var)
register WORD_LIST *list;
int local_var;
{
int flags_on, flags_off, *flags, any_failed, assign_error, pflag, nodefs, opt;
int flags_on, flags_off, *flags;
int any_failed, assign_error, pflag, nodefs, opt;
char *t, *subscript_start;
SHELL_VAR *var;
FUNCTION_DEF *shell_fn;
@@ -150,8 +152,19 @@ declare_internal (list, local_var)
case 'a':
#if defined (ARRAY_VARS)
*flags |= att_array;
#endif
break;
#else
builtin_usage ();
return (EX_USAGE);
#endif
case 'A':
#if defined (ARRAY_VARS)
*flags |= att_assoc;
break;
#else
builtin_usage ();
return (EX_USAGE);
#endif
case 'p':
if (local_var == 0)
pflag++;
@@ -186,7 +199,7 @@ declare_internal (list, local_var)
/* If there are no more arguments left, then we just want to show
some variables. */
if (list == 0) /* declare -[afFirtx] */
if (list == 0) /* declare -[aAfFirtx] */
{
/* Show local variables defined at this context level if this is
the `local' builtin. */
@@ -215,7 +228,7 @@ declare_internal (list, local_var)
return (sh_chkwrite (EXECUTION_SUCCESS));
}
if (pflag) /* declare -p [-afFirtx] name [name...] */
if (pflag) /* declare -p [-aAfFirtx] name [name...] */
{
for (any_failed = 0; list; list = list->next)
{
@@ -232,7 +245,7 @@ declare_internal (list, local_var)
#define NEXT_VARIABLE() free (name); list = list->next; continue
/* There are arguments left, so we are making variables. */
while (list) /* declare [-afFirx] name [name ...] */
while (list) /* declare [-aAfFirx] name [name ...] */
{
char *value, *name;
int offset, aflags;
@@ -244,7 +257,7 @@ declare_internal (list, local_var)
offset = assignment (name, 0);
aflags = 0;
if (offset) /* declare [-afFirx] name=value */
if (offset) /* declare [-aAfFirx] name=value */
{
name[offset] = '\0';
value = name + offset + 1;
@@ -291,7 +304,9 @@ declare_internal (list, local_var)
if (variable_context && ((flags_on & att_function) == 0))
{
#if defined (ARRAY_VARS)
if ((flags_on & att_array) || making_array_special)
if (flags_on & att_assoc)
var = make_local_assoc_variable (name);
else if ((flags_on & att_array) || making_array_special)
var = make_local_array_variable (name);
else
#endif
@@ -364,7 +379,7 @@ declare_internal (list, local_var)
NEXT_VARIABLE ();
}
}
else /* declare -[airx] name [name...] */
else /* declare -[aAirx] name [name...] */
{
/* Non-null if we just created or fetched a local variable. */
if (var == 0)
@@ -373,7 +388,9 @@ declare_internal (list, local_var)
if (var == 0)
{
#if defined (ARRAY_VARS)
if ((flags_on & att_array) || making_array_special)
if (flags_on & att_assoc)
var = make_new_assoc_variable (name);
else if ((flags_on & att_array) || making_array_special)
var = make_new_array_variable (name);
else
#endif
@@ -399,7 +416,7 @@ declare_internal (list, local_var)
}
#if defined (ARRAY_VARS)
if ((making_array_special || (flags_on & att_array) || array_p (var)) && offset)
if ((making_array_special || (flags_on & (att_array|att_assoc)) || array_p (var) || assoc_p (var)) && offset)
{
int vlen;
vlen = STRLEN (value);
@@ -410,16 +427,37 @@ declare_internal (list, local_var)
simple_array_assign = 1;
}
/* Cannot use declare +a name to remove an array variable. */
if ((flags_off & att_array) && array_p (var))
/* Cannot use declare +a name or declare +A name to remove an
array variable. */
if (((flags_off & att_array) && array_p (var)) || ((flags_off & att_assoc) && assoc_p (var)))
{
builtin_error (_("%s: cannot destroy array variables in this way"), name);
any_failed++;
NEXT_VARIABLE ();
}
/* declare -a name makes name an array variable. */
if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0)
if ((flags_on & att_array) && assoc_p (var))
{
builtin_error (_("%s: cannot convert associative to indexed array"), name);
any_failed++;
NEXT_VARIABLE ();
}
if ((flags_on & att_assoc) && array_p (var))
{
builtin_error (_("%s: cannot convert indexed to associative array"), name);
any_failed++;
NEXT_VARIABLE ();
}
/* declare -A name[[n]] makes name an associative array variable. */
if (flags_on & att_assoc)
{
if (assoc_p (var) == 0)
var = convert_var_to_assoc (var);
}
/* declare -a name[[n]] or declare name[n] makes name an indexed
array variable. */
else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0)
var = convert_var_to_array (var);
#endif /* ARRAY_VARS */
+2 -2
View File
@@ -558,7 +558,7 @@ initialize_shell_options (no_shellopts)
/* set up any shell options we may have inherited. */
if (var && imported_p (var))
{
temp = (array_p (var)) ? (char *)NULL : savestring (value_cell (var));
temp = (array_p (var) || assoc_p (var)) ? (char *)NULL : savestring (value_cell (var));
if (temp)
{
parse_shellopts (temp);
@@ -819,7 +819,7 @@ unset_builtin (list)
#if defined (ARRAY_VARS)
if (var && unset_array)
{
if (array_p (var) == 0)
if (array_p (var) == 0 && assoc_p (var) == 0)
{
builtin_error (_("%s: not an array variable"), name);
NEXT_VARIABLE ();
+31 -9
View File
@@ -91,7 +91,8 @@ changed by subsequent assignment. If VALUE is supplied, assign VALUE
before marking as read-only.
Options:
-a refer to array variables
-a refer to indexed array variables
-A refer to associative array variables
-f refer to shell functions
-p display a list of all readonly variables and functions
@@ -111,7 +112,7 @@ readonly_builtin (list)
}
#if defined (ARRAY_VARS)
# define ATTROPTS "afnp"
# define ATTROPTS "aAfnp"
#else
# define ATTROPTS "fnp"
#endif
@@ -125,7 +126,8 @@ set_or_show_attributes (list, attribute, nodefs)
int attribute, nodefs;
{
register SHELL_VAR *var;
int assign, undo, functions_only, arrays_only, any_failed, assign_error, opt;
int assign, undo, any_failed, assign_error, opt;
int functions_only, arrays_only, assoc_only;
int aflags;
char *name;
#if defined (ARRAY_VARS)
@@ -133,7 +135,8 @@ set_or_show_attributes (list, attribute, nodefs)
WORD_DESC *w;
#endif
undo = functions_only = arrays_only = any_failed = assign_error = 0;
functions_only = arrays_only = assoc_only = 0;
undo = any_failed = assign_error = 0;
/* Read arguments from the front of the list. */
reset_internal_getopt ();
while ((opt = internal_getopt (list, ATTROPTS)) != -1)
@@ -148,8 +151,11 @@ set_or_show_attributes (list, attribute, nodefs)
break;
#if defined (ARRAY_VARS)
case 'a':
arrays_only = 1;
break;
arrays_only = 1;
break;
case 'A':
assoc_only = 1;
break;
#endif
case 'p':
break;
@@ -221,11 +227,11 @@ set_or_show_attributes (list, attribute, nodefs)
#if defined (ARRAY_VARS)
/* Let's try something here. Turn readonly -a xxx=yyy into
declare -ra xxx=yyy and see what that gets us. */
if (arrays_only)
if (arrays_only || assoc_only)
{
tlist = list->next;
list->next = (WORD_LIST *)NULL;
w = make_word ("-ra");
w = arrays_only ? make_word ("-ra") : make_word ("-rA");
nlist = make_word_list (w, list);
opt = declare_builtin (nlist);
if (opt != EXECUTION_SUCCESS)
@@ -272,6 +278,12 @@ set_or_show_attributes (list, attribute, nodefs)
if (attribute != att_array)
attribute &= ~att_array;
}
else if (attribute & att_assoc)
{
assoc_only++;
if (attribute != att_assoc)
attribute &= ~att_assoc;
}
#endif
if (variable_list)
@@ -281,6 +293,8 @@ set_or_show_attributes (list, attribute, nodefs)
#if defined (ARRAY_VARS)
if (arrays_only && array_p (var) == 0)
continue;
else if (assoc_only && assoc_p (var) == 0)
continue;
#endif
if ((var->attributes & attribute))
{
@@ -344,6 +358,9 @@ show_var_attributes (var, pattr, nodefs)
#if defined (ARRAY_VARS)
if (array_p (var))
flags[i++] = 'a';
if (assoc_p (var))
flags[i++] = 'A';
#endif
if (function_p (var))
@@ -366,6 +383,9 @@ show_var_attributes (var, pattr, nodefs)
#if defined (ARRAY_VARS)
if (array_p (var))
flags[i++] = 'a';
if (assoc_p (var))
flags[i++] = 'A';
#endif
if (function_p (var))
@@ -393,8 +413,10 @@ show_var_attributes (var, pattr, nodefs)
printf ("%s ", this_command_name);
#if defined (ARRAY_VARS)
if (array_p (var))
if (array_p (var))
print_array_assignment (var, 1);
else if (assoc_p (var))
print_assoc_assignment (var, 1);
else
#endif
/* force `readonly' and `export' to not print out function definitions
+32 -10
View File
@@ -91,7 +91,8 @@ changed by subsequent assignment. If VALUE is supplied, assign VALUE
before marking as read-only.
Options:
-a refer to array variables
-a refer to indexed array variables
-A refer to associative array variables
-f refer to shell functions
-p display a list of all readonly variables and functions
@@ -111,7 +112,7 @@ readonly_builtin (list)
}
#if defined (ARRAY_VARS)
# define ATTROPTS "afnp"
# define ATTROPTS "aAfnp"
#else
# define ATTROPTS "fnp"
#endif
@@ -125,7 +126,8 @@ set_or_show_attributes (list, attribute, nodefs)
int attribute, nodefs;
{
register SHELL_VAR *var;
int assign, undo, functions_only, arrays_only, any_failed, assign_error, opt;
int assign, undo, any_failed, assign_error, opt;
int functions_only, arrays_only, assoc_only;
int aflags;
char *name;
#if defined (ARRAY_VARS)
@@ -133,7 +135,8 @@ set_or_show_attributes (list, attribute, nodefs)
WORD_DESC *w;
#endif
undo = functions_only = arrays_only = any_failed = assign_error = 0;
functions_only = arrays_only = assoc_only = 0;
undo = any_failed = assign_error = 0;
/* Read arguments from the front of the list. */
reset_internal_getopt ();
while ((opt = internal_getopt (list, ATTROPTS)) != -1)
@@ -148,8 +151,11 @@ set_or_show_attributes (list, attribute, nodefs)
break;
#if defined (ARRAY_VARS)
case 'a':
arrays_only = 1;
break;
arrays_only = 1;
break;
case 'A':
assoc_only = 1;
break;
#endif
case 'p':
break;
@@ -221,11 +227,11 @@ set_or_show_attributes (list, attribute, nodefs)
#if defined (ARRAY_VARS)
/* Let's try something here. Turn readonly -a xxx=yyy into
declare -ra xxx=yyy and see what that gets us. */
if (arrays_only)
if (arrays_only || assoc_only)
{
tlist = list->next;
list->next = (WORD_LIST *)NULL;
w = make_word ("-ra");
w = arrays_only ? make_word ("-ra") : make_word ("-rA");
nlist = make_word_list (w, list);
opt = declare_builtin (nlist);
if (opt != EXECUTION_SUCCESS)
@@ -272,6 +278,12 @@ set_or_show_attributes (list, attribute, nodefs)
if (attribute != att_array)
attribute &= ~att_array;
}
else if (attribute & att_assoc)
{
assoc_only++;
if (attribute != att_assoc)
attribute &= ~att_assoc;
}
#endif
if (variable_list)
@@ -281,6 +293,8 @@ set_or_show_attributes (list, attribute, nodefs)
#if defined (ARRAY_VARS)
if (arrays_only && array_p (var) == 0)
continue;
if (assoc_only && assoc_p (var) == 0)
continue;
#endif
if ((var->attributes & attribute))
{
@@ -333,7 +347,7 @@ show_var_attributes (var, pattr, nodefs)
SHELL_VAR *var;
int pattr, nodefs;
{
char flags[8], *x;
char flags[16], *x;
int i;
i = 0;
@@ -344,6 +358,9 @@ show_var_attributes (var, pattr, nodefs)
#if defined (ARRAY_VARS)
if (array_p (var))
flags[i++] = 'a';
if (assoc_p (var))
flags[i++] = 'A';
#endif
if (function_p (var))
@@ -366,6 +383,9 @@ show_var_attributes (var, pattr, nodefs)
#if defined (ARRAY_VARS)
if (array_p (var))
flags[i++] = 'a';
if (assoc_p (var))
flags[i++] = 'A';
#endif
if (function_p (var))
@@ -393,8 +413,10 @@ show_var_attributes (var, pattr, nodefs)
printf ("%s ", this_command_name);
#if defined (ARRAY_VARS)
if (array_p (var))
if (array_p (var))
print_array_assignment (var, 1);
else if (assoc_p (var))
print_assoc_assignment (var, 1);
else
#endif
/* force `readonly' and `export' to not print out function definitions
+22 -2
View File
@@ -1,7 +1,7 @@
/* command.h -- The structures used internally to represent commands, and
the extern declarations of the functions used to create them. */
/* Copyright (C) 1993-2005 Free Software Foundation, Inc.
/* Copyright (C) 1993-2008 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -66,7 +66,7 @@ enum r_instruction {
/* Command Types: */
enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select,
cm_connection, cm_function_def, cm_until, cm_group,
cm_arith, cm_cond, cm_arith_for, cm_subshell };
cm_arith, cm_cond, cm_arith_for, cm_subshell, cm_coproc };
/* Possible values for the `flags' field of a WORD_DESC. */
#define W_HASDOLLAR 0x000001 /* Dollar sign present. */
@@ -162,6 +162,7 @@ typedef struct element {
#define CMD_AMPERSAND 0x200 /* command & */
#define CMD_STDIN_REDIR 0x400 /* async command needs implicit </dev/null */
#define CMD_COMMAND_BUILTIN 0x0800 /* command executed by `command' builtin */
#define CMD_COPROC_SUBSHELL 0x1000
/* What a command looks like. */
typedef struct command {
@@ -191,6 +192,7 @@ typedef struct command {
struct arith_for_com *ArithFor;
#endif
struct subshell_com *Subshell;
struct coproc_com *Coproc;
} value;
} COMMAND;
@@ -332,7 +334,25 @@ typedef struct subshell_com {
COMMAND *command;
} SUBSHELL_COM;
typedef struct coproc {
char *c_name;
pid_t c_pid;
int c_rfd;
int c_wfd;
int c_rsave;
int c_wsave;
int c_flags;
int c_status;
} Coproc;
typedef struct coproc_com {
int flags;
char *name;
COMMAND *command;
} COPROC_COM;
extern COMMAND *global_command;
extern Coproc sh_coproc;
/* Possible command errors */
#define CMDERR_DEFAULT 0
+7
View File
@@ -155,6 +155,13 @@
/* Define AFS if you are using Transarc's AFS. */
#undef AFS
/* Define for case-modifying variable attributes; variables modified on
assignment */
#undef CASEMOD_ATTRS
/* Define for case-modifying word expansions */
#undef CASEMOD_EXPANSIONS
#undef ENABLE_NLS
/* End of configuration settings controllable by autoconf. */
Vendored
+30 -1
View File
@@ -1,5 +1,5 @@
#! /bin/sh
# From configure.in for Bash 4.0, version 4.001.
# From configure.in for Bash 4.0, version 4.002.
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.61 for bash 4.0-devel.
#
@@ -1365,6 +1365,10 @@ Optional Features:
--enable-bang-history turn on csh-style history substitution
--enable-brace-expansion
include brace expansion
--enable-casemod-attributes
include case-modifying variable attributes
--enable-casemod-expansions
include case-modifying word expansions
--enable-command-timing enable the time reserved word and command timing
--enable-cond-command enable the conditional command
--enable-cond-regexp enable extended regular expression matching in
@@ -2259,6 +2263,8 @@ opt_separate_help=no
opt_multibyte=yes
opt_debugger=yes
opt_single_longdoc_strings=yes
opt_casemod_attrs=yes
opt_casemod_expansions=yes
opt_static_link=no
opt_profiling=no
@@ -2278,6 +2284,7 @@ if test $opt_minimal_config = yes; then
opt_extended_glob=no opt_cond_command=no opt_arith_for_command=no
opt_net_redirs=no opt_progcomp=no opt_separate_help=no
opt_multibyte=yes opt_cond_regexp=no
opt_casemod_attrs=no opt_casemod_expansions=no
fi
# Check whether --enable-alias was given.
@@ -2305,6 +2312,16 @@ if test "${enable_brace_expansion+set}" = set; then
enableval=$enable_brace_expansion; opt_brace_expansion=$enableval
fi
# Check whether --enable-casemod-attributes was given.
if test "${enable_casemod_attributes+set}" = set; then
enableval=$enable_casemod_attributes; opt_casemod_attrs=$enableval
fi
# Check whether --enable-casemod-expansions was given.
if test "${enable_casemod_expansions+set}" = set; then
enableval=$enable_casemod_expansions; opt_casemod_expansions=$enableval
fi
# Check whether --enable-command-timing was given.
if test "${enable_command_timing+set}" = set; then
enableval=$enable_command_timing; opt_command_timing=$enableval
@@ -2575,6 +2592,18 @@ cat >>confdefs.h <<\_ACEOF
#define DEBUGGER 1
_ACEOF
fi
if test $opt_casemod_attrs = yes; then
cat >>confdefs.h <<\_ACEOF
#define CASEMOD_ATTRS 1
_ACEOF
fi
if test $opt_casemod_expansions = yes; then
cat >>confdefs.h <<\_ACEOF
#define CASEMOD_EXPANSIONS 1
_ACEOF
fi
if test $opt_memscramble = yes; then
+12 -1
View File
@@ -22,7 +22,7 @@ dnl Process this file with autoconf to produce a configure script.
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
AC_REVISION([for Bash 4.0, version 4.001])dnl
AC_REVISION([for Bash 4.0, version 4.002])dnl
define(bashvers, 4.0)
define(relstatus, devel)
@@ -183,6 +183,8 @@ opt_separate_help=no
opt_multibyte=yes
opt_debugger=yes
opt_single_longdoc_strings=yes
opt_casemod_attrs=yes
opt_casemod_expansions=yes
dnl options that affect how bash is compiled and linked
opt_static_link=no
@@ -202,6 +204,7 @@ if test $opt_minimal_config = yes; then
opt_extended_glob=no opt_cond_command=no opt_arith_for_command=no
opt_net_redirs=no opt_progcomp=no opt_separate_help=no
opt_multibyte=yes opt_cond_regexp=no
opt_casemod_attrs=no opt_casemod_expansions=no
fi
AC_ARG_ENABLE(alias, AC_HELP_STRING([--enable-alias], [enable shell aliases]), opt_alias=$enableval)
@@ -209,6 +212,8 @@ AC_ARG_ENABLE(arith-for-command, AC_HELP_STRING([--enable-arith-for-command], [e
AC_ARG_ENABLE(array-variables, AC_HELP_STRING([--enable-array-variables], [include shell array variables]), opt_array_variables=$enableval)
AC_ARG_ENABLE(bang-history, AC_HELP_STRING([--enable-bang-history], [turn on csh-style history substitution]), opt_bang_history=$enableval)
AC_ARG_ENABLE(brace-expansion, AC_HELP_STRING([--enable-brace-expansion], [include brace expansion]), opt_brace_expansion=$enableval)
AC_ARG_ENABLE(casemod-attributes, AC_HELP_STRING([--enable-casemod-attributes], [include case-modifying variable attributes]), opt_casemod_attrs=$enableval)
AC_ARG_ENABLE(casemod-expansions, AC_HELP_STRING([--enable-casemod-expansions], [include case-modifying word expansions]), opt_casemod_expansions=$enableval)
AC_ARG_ENABLE(command-timing, AC_HELP_STRING([--enable-command-timing], [enable the time reserved word and command timing]), opt_command_timing=$enableval)
AC_ARG_ENABLE(cond-command, AC_HELP_STRING([--enable-cond-command], [enable the conditional command]), opt_cond_command=$enableval)
AC_ARG_ENABLE(cond-regexp, AC_HELP_STRING([--enable-cond-regexp], [enable extended regular expression matching in conditional commands]), opt_cond_regexp=$enableval)
@@ -311,6 +316,12 @@ fi
if test $opt_debugger = yes; then
AC_DEFINE(DEBUGGER)
fi
if test $opt_casemod_attrs = yes; then
AC_DEFINE(CASEMOD_ATTRS)
fi
if test $opt_casemod_expansions = yes; then
AC_DEFINE(CASEMOD_EXPANSIONS)
fi
if test $opt_memscramble = yes; then
AC_DEFINE(MEMSCRAMBLE)
+53 -19
View File
@@ -5,12 +5,12 @@
.\" Case Western Reserve University
.\" chet@po.cwru.edu
.\"
.\" Last Change: Mon Jun 2 20:32:53 EDT 2008
.\" Last Change: Sun Jun 29 22:44:15 EDT 2008
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
.TH BASH 1 "2008 June 2" "GNU Bash-4.0"
.TH BASH 1 "2008 June 29" "GNU Bash-4.0"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
@@ -1130,7 +1130,9 @@ When += is applied to an array variable using compound assignment (see
.B Arrays
below), the
variable's value is not unset (as it is when using =), and new values are
appended to the array beginning at one greater than the array's maximum index.
appended to the array beginning at one greater than the array's maximum index
(for indexed arrays) or added as additional key\-value pairs in an
associative array.
When applied to a string-valued variable, \fIvalue\fP is expanded and
appended to the variable's value.
.SS Positional Parameters
@@ -1264,6 +1266,12 @@ Expands to the process id of the current \fBbash\fP process.
This differs from \fB$$\fP under certain circumstances, such as subshells
that do not require \fBbash\fP to be re-initialized.
.TP
.B BASH_ALIASES
An associative array variable whose members correspond to the internal
list of aliases as maintained by the \fBalias\fP builtin
Elements added to this array appear in the alias list; unsetting array
elements cause aliases to be removed from the alias list.
.TP
.B BASH_ARGC
An array variable whose values are the number of parameters in each
frame of the current \fBbash\fP execution call stack.
@@ -1292,6 +1300,12 @@ option to the
.B shopt
builtin below)
.TP
.B BASH_CMDS
An associative array variable whose members correspond to the internal
hash table of commands as maintained by the \fBhash\fP builtin.
Elements added to this array appear in the hash table; unsetting array
elements cause commands to be removed from the hash table.
.TP
.B BASH_COMMAND
The command currently being executed or about to be executed, unless the
shell is executing a command as the result of a trap,
@@ -2101,19 +2115,23 @@ parser to treat the rest of the line as a comment.
.PD
.SS Arrays
.B Bash
provides one-dimensional array variables. Any variable may be used as
an array; the
provides one-dimensional indexed and associative array variables.
Any variable may be used as an array; the
.B declare
builtin will explicitly declare an array. There is no maximum
builtin will explicitly declare an array.
There is no maximum
limit on the size of an array, nor any requirement that members
be indexed or assigned contiguously. Arrays are indexed using
integers and are zero-based.
be indexed or assigned contiguously.
Indexed arrays are referenced using integers (including arithmetic
expressions) and are zero-based; associative arrays use arbitrary
strings.
.PP
An array is created automatically if any variable is assigned to using
the syntax \fIname\fP[\fIsubscript\fP]=\fIvalue\fP. The
An indexed array is created automatically if any variable is assigned to
using the syntax \fIname\fP[\fIsubscript\fP]=\fIvalue\fP. The
.I subscript
is treated as an arithmetic expression that must evaluate to a number
greater than or equal to zero. To explicitly declare an array, use
greater than or equal to zero. To explicitly declare an indexed array,
use
.B declare \-a \fIname\fP
(see
.SM
@@ -2127,13 +2145,19 @@ and
.B readonly
builtins. Each attribute applies to all members of an array.
.PP
Associative arrays are created using
.BR declare \-A \fIname\fP .
.PP
Arrays are assigned to using compound assignments of the form
\fIname\fP=\fB(\fPvalue\fI1\fP ... value\fIn\fP\fB)\fP, where each
\fIvalue\fP is of the form [\fIsubscript\fP]=\fIstring\fP. Only
\fIstring\fP is required. If
\fIstring\fP is required. When using indexed arrays, if
the optional brackets and subscript are supplied, that index is assigned to;
otherwise the index of the element assigned is the last index assigned
to by the statement plus one. Indexing starts at zero.
.PP
When assigning to an associative array, the subscript is required.
.PP
This syntax is also accepted by the
.B declare
builtin. Individual array elements may be assigned to using the
@@ -2164,7 +2188,7 @@ above). ${#\fIname\fP[\fIsubscript\fP]} expands to the length of
${\fIname\fP[\fIsubscript\fP]}. If \fIsubscript\fP is \fB*\fP or
\fB@\fP, the expansion is the number of elements in the array.
Referencing an array variable without a subscript is equivalent to
referencing element zero.
referencing the array with a subscript of 0.
.PP
The
.B unset
@@ -2183,7 +2207,10 @@ and
.B readonly
builtins each accept a
.B \-a
option to specify an array. The
option to specify an indexed array and a
.B \-A
option to specify an associative array.
The
.B read
builtin accepts a
.B \-a
@@ -6618,10 +6645,10 @@ is greater than the number of enclosing loops, the last enclosing loop
(the ``top-level'' loop) is resumed.
The return value is 0 unless \fIn\fP is not greater than or equal to 1.
.TP
\fBdeclare\fP [\fB\-afFirtx\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...]
\fBdeclare\fP [\fB\-aAfFirtx\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...]
.PD 0
.TP
\fBtypeset\fP [\fB\-afFirtx\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...]
\fBtypeset\fP [\fB\-aAfFirtx\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...]
.PD
Declare variables and/or give them attributes.
If no \fIname\fPs are given then display the values of variables.
@@ -6657,7 +6684,12 @@ to give variables attributes:
.PD 0
.TP
.B \-a
Each \fIname\fP is an array variable (see
Each \fIname\fP is an indexed array variable (see
.B Arrays
above).
.TP
.B \-A
Each \fIname\fP is an associative array variable (see
.B Arrays
above).
.TP
@@ -7770,7 +7802,7 @@ times out, or an invalid file descriptor is supplied as the argument to
\fB\-u\fP.
.RE
.TP
\fBreadonly\fP [\fB\-apf\fP] [\fIname\fP[=\fIword\fP] ...]
\fBreadonly\fP [\fB\-aApf\fP] [\fIname\fP[=\fIword\fP] ...]
.PD
The given
\fInames\fP are marked readonly; the values of these
@@ -7783,7 +7815,9 @@ option is supplied, the functions corresponding to the
marked.
The
.B \-a
option restricts the variables to arrays.
option restricts the variables to indexed arrays; the
.B \-A
option restricts the variables to associative arrays.
If no
.I name
arguments are given, or if the
+52 -17
View File
@@ -1130,7 +1130,9 @@ When += is applied to an array variable using compound assignment (see
.B Arrays
below), the
variable's value is not unset (as it is when using =), and new values are
appended to the array beginning at one greater than the array's maximum index.
appended to the array beginning at one greater than the array's maximum index
(for indexed arrays) or added as additional key\-value pairs in an
associative array.
When applied to a string-valued variable, \fIvalue\fP is expanded and
appended to the variable's value.
.SS Positional Parameters
@@ -1264,6 +1266,12 @@ Expands to the process id of the current \fBbash\fP process.
This differs from \fB$$\fP under certain circumstances, such as subshells
that do not require \fBbash\fP to be re-initialized.
.TP
.B BASH_ALIASES
An associative array variable whose members correspond to the internal
list of aliases as maintained by the \fBalias\fP builtin
Elements added to this array appear in the alias list; unsetting array
elements cause aliases to be removed from the alias list.
.TP
.B BASH_ARGC
An array variable whose values are the number of parameters in each
frame of the current \fBbash\fP execution call stack.
@@ -1292,6 +1300,12 @@ option to the
.B shopt
builtin below)
.TP
.B BASH_CMDS
An associative array variable whose members correspond to the internal
hash table of commands as maintained by the \fBhash\fP builtin.
Elements added to this array appear in the hash table; unsetting array
elements cause commands to be removed from the hash table.
.TP
.B BASH_COMMAND
The command currently being executed or about to be executed, unless the
shell is executing a command as the result of a trap,
@@ -2101,19 +2115,23 @@ parser to treat the rest of the line as a comment.
.PD
.SS Arrays
.B Bash
provides one-dimensional array variables. Any variable may be used as
an array; the
provides one-dimensional indexed and associative array variables.
Any variable may be used as an array; the
.B declare
builtin will explicitly declare an array. There is no maximum
builtin will explicitly declare an array.
There is no maximum
limit on the size of an array, nor any requirement that members
be indexed or assigned contiguously. Arrays are indexed using
integers and are zero-based.
be indexed or assigned contiguously.
Indexed arrays are referenced using integers (including arithmetic
expressions) and are zero-based; associative arrays use arbitrary
strings.
.PP
An array is created automatically if any variable is assigned to using
the syntax \fIname\fP[\fIsubscript\fP]=\fIvalue\fP. The
An indexed array is created automatically if any variable is assigned to
using the syntax \fIname\fP[\fIsubscript\fP]=\fIvalue\fP. The
.I subscript
is treated as an arithmetic expression that must evaluate to a number
greater than or equal to zero. To explicitly declare an array, use
greater than or equal to zero. To explicitly declare an indexed array,
use
.B declare \-a \fIname\fP
(see
.SM
@@ -2127,13 +2145,19 @@ and
.B readonly
builtins. Each attribute applies to all members of an array.
.PP
Associative arrays are created using
.BR declare \-A \fIname\fP .
.PP
Arrays are assigned to using compound assignments of the form
\fIname\fP=\fB(\fPvalue\fI1\fP ... value\fIn\fP\fB)\fP, where each
\fIvalue\fP is of the form [\fIsubscript\fP]=\fIstring\fP. Only
\fIstring\fP is required. If
\fIstring\fP is required. When using indexed arrays, if
the optional brackets and subscript are supplied, that index is assigned to;
otherwise the index of the element assigned is the last index assigned
to by the statement plus one. Indexing starts at zero.
.PP
When assigning to an associative array, the subscript is required.
.PP
This syntax is also accepted by the
.B declare
builtin. Individual array elements may be assigned to using the
@@ -2164,7 +2188,7 @@ above). ${#\fIname\fP[\fIsubscript\fP]} expands to the length of
${\fIname\fP[\fIsubscript\fP]}. If \fIsubscript\fP is \fB*\fP or
\fB@\fP, the expansion is the number of elements in the array.
Referencing an array variable without a subscript is equivalent to
referencing element zero.
referencing the array with a subscript of 0.
.PP
The
.B unset
@@ -2183,7 +2207,10 @@ and
.B readonly
builtins each accept a
.B \-a
option to specify an array. The
option to specify an indexed array and a
.B \-A
option to specify an associative array.
The
.B read
builtin accepts a
.B \-a
@@ -6618,10 +6645,10 @@ is greater than the number of enclosing loops, the last enclosing loop
(the ``top-level'' loop) is resumed.
The return value is 0 unless \fIn\fP is not greater than or equal to 1.
.TP
\fBdeclare\fP [\fB\-afFirtx\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...]
\fBdeclare\fP [\fB\-aAfFirtx\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...]
.PD 0
.TP
\fBtypeset\fP [\fB\-afFirtx\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...]
\fBtypeset\fP [\fB\-aAfFirtx\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...]
.PD
Declare variables and/or give them attributes.
If no \fIname\fPs are given then display the values of variables.
@@ -6657,7 +6684,12 @@ to give variables attributes:
.PD 0
.TP
.B \-a
Each \fIname\fP is an array variable (see
Each \fIname\fP is an indexed array variable (see
.B Arrays
above).
.TP
.B \-A
Each \fIname\fP is an associative array variable (see
.B Arrays
above).
.TP
@@ -7754,6 +7786,7 @@ the decimal point.
This option is only effective if \fBread\fP is reading input from a
terminal, pipe, or other special file; it has no effect when reading
from regular files.
The exit status is greater than 128 if the timeout is exceeded.
.TP
.B \-u \fIfd\fP
Read input from file descriptor \fIfd\fP.
@@ -7769,7 +7802,7 @@ times out, or an invalid file descriptor is supplied as the argument to
\fB\-u\fP.
.RE
.TP
\fBreadonly\fP [\fB\-apf\fP] [\fIname\fP[=\fIword\fP] ...]
\fBreadonly\fP [\fB\-aApf\fP] [\fIname\fP[=\fIword\fP] ...]
.PD
The given
\fInames\fP are marked readonly; the values of these
@@ -7782,7 +7815,9 @@ option is supplied, the functions corresponding to the
marked.
The
.B \-a
option restricts the variables to arrays.
option restricts the variables to indexed arrays; the
.B \-A
option restricts the variables to associative arrays.
If no
.I name
arguments are given, or if the
+56 -15
View File
@@ -1234,7 +1234,8 @@ When @samp{+=} is applied to an array variable using compound assignment
(@pxref{Arrays}), the
variable's value is not unset (as it is when using @samp{=}), and new
values are appended to the array beginning at one greater than the array's
maximum index.
maximum index (for indexed arrays), or added as additional key-value pairs
in an associative array.
When applied to a string-valued variable, @var{value} is expanded and
appended to the variable's value.
@@ -2921,13 +2922,15 @@ is supplied.
@item readonly
@btindex readonly
@example
readonly [-apf] [@var{name}[=@var{value}]] @dots{}
readonly [-aApf] [@var{name}[=@var{value}]] @dots{}
@end example
Mark each @var{name} as readonly.
The values of these names may not be changed by subsequent assignment.
If the @option{-f} option is supplied, each @var{name} refers to a shell
function.
The @option{-a} option means each @var{name} refers to an array variable.
The @option{-a} option means each @var{name} refers to an indexed
array variable; the @option{-A} option means each @var{name} refers
to an associative array variable.
If no @var{name} arguments are given, or if the @option{-p}
option is supplied, a list of all readonly names is printed.
The @option{-p} option causes output to be displayed in a format that
@@ -3318,7 +3321,7 @@ zero if @var{command} is found, and non-zero if not.
@item declare
@btindex declare
@example
declare [-afFirtx] [-p] [@var{name}[=@var{value}] @dots{}]
declare [-aAfFirtx] [-p] [@var{name}[=@var{value}] @dots{}]
@end example
Declare variables and give them attributes. If no @var{name}s
@@ -3347,7 +3350,10 @@ the specified attributes or to give variables attributes:
@table @code
@item -a
Each @var{name} is an array variable (@pxref{Arrays}).
Each @var{name} is an indexed array variable (@pxref{Arrays}).
@item -A
Each @var{name} is an associative array variable (@pxref{Arrays}).
@item -f
Use function names only.
@@ -4518,6 +4524,13 @@ Expands to the process id of the current Bash process.
This differs from @code{$$} under certain circumstances, such as subshells
that do not require Bash to be re-initialized.
@item BASH_ALIASES
An associative array variable whose members correspond to the internal
list of aliases as maintained by the @code{alias} builtin
(@pxref{Bourne Shell Builtins}).
Elements added to this array appear in the alias list; unsetting array
elements cause aliases to be removed from the alias list.
@item BASH_ARGC
An array variable whose values are the number of parameters in each
frame of the current bash execution call stack. The number of
@@ -4541,6 +4554,13 @@ The shell sets @code{BASH_ARGV} only when in extended debugging mode
for a description of the @code{extdebug} option to the @code{shopt}
builtin).
@item BASH_CMDS
An associative array variable whose members correspond to the internal
hash table of commands as maintained by the @code{hash} builtin
(@pxref{Bourne Shell Builtins}).
Elements added to this array appear in the hash table; unsetting array
elements cause commands to be removed from the hash table.
@item BASH_COMMAND
The command currently being executed or about to be executed, unless the
shell is executing a command as the result of a trap,
@@ -5807,14 +5827,18 @@ For almost every purpose, shell functions are preferred over aliases.
@section Arrays
@cindex arrays
Bash provides one-dimensional array variables. Any variable may be used as
an array; the @code{declare} builtin will explicitly declare an array.
Bash provides one-dimensional indexed and associative array variables.
Any variable may be used as an array; the @code{declare} builtin will
explicitly declare an array.
There is no maximum
limit on the size of an array, nor any requirement that members
be indexed or assigned contiguously. Arrays are zero-based.
be indexed or assigned contiguously.
Indexed arrays are referenced using integers (including arithmetic
expressions (@pxref{Shell Arithmetic}) and are zero-based;
associative arrays use arbitrary strings.
An array is created automatically if any variable is assigned to using
the syntax
An indexed array is created automatically if any variable is assigned to
using the syntax
@example
name[@var{subscript}]=@var{value}
@end example
@@ -5837,16 +5861,25 @@ specified for an array variable using the @code{declare} and
@code{readonly} builtins. Each attribute applies to all members of
an array.
Associative arrays are created using
@example
declare -A @var{name}.
@end example
Arrays are assigned to using compound assignments of the form
@example
name=(value@var{1} @dots{} value@var{n})
@end example
@noindent
where each
@var{value} is of the form @code{[[@var{subscript}]=]}@var{string}. If
@var{value} is of the form @code{[[@var{subscript}]=]}@var{string}.
When using indexed arrays, if
the optional subscript is supplied, that index is assigned to;
otherwise the index of the element assigned is the last index assigned
to by the statement plus one. Indexing starts at zero.
When assigning to an associative array, the subscript is required.
This syntax is also accepted by the @code{declare}
builtin. Individual array elements may be assigned to using the
@code{name[}@var{subscript}@code{]=}@var{value} syntax introduced above.
@@ -5875,7 +5908,7 @@ expansion of the special parameters @samp{@@} and @samp{*}.
If @var{subscript} is @samp{@@} or
@samp{*}, the expansion is the number of elements in the array.
Referencing an array variable without a subscript is equivalent to
referencing element zero.
referencing with a subscript of 0.
The @code{unset} builtin is used to destroy arrays.
@code{unset} @var{name}[@var{subscript}]
@@ -5887,9 +5920,9 @@ entire array. A subscript of @samp{*} or @samp{@@} also removes the
entire array.
The @code{declare}, @code{local}, and @code{readonly}
builtins each accept a @option{-a}
option to specify an array. The @code{read}
builtin accepts a @option{-a}
builtins each accept a @option{-a} option to specify an indexed
array and a @option{-A} option to specify an associative array.
The @code{read} builtin accepts a @option{-a}
option to assign a list of words read from the standard input
to an array, and can read values from the standard input into
individual array elements. The @code{set} and @code{declare}
@@ -7020,6 +7053,14 @@ Include @code{csh}-like brace expansion
( @code{b@{a,b@}c} @expansion{} @code{bac bbc} ).
See @ref{Brace Expansion}, for a complete description.
@item --enable-casemod-attributes
Include support for case-modifying attributes in the @code{declare} builtin
and assignment statements. Variables with the @var{uppercase} attribute,
for example, will have their values converted to uppercase upon assignment.
@item --enable-casemod-expansion
Include support for case-modifying word expansions.
@item --enable-command-timing
Include support for recognizing @code{time} as a reserved word and for
displaying timing statistics for the pipeline following @code{time}
+57 -15
View File
@@ -1234,7 +1234,8 @@ When @samp{+=} is applied to an array variable using compound assignment
(@pxref{Arrays}), the
variable's value is not unset (as it is when using @samp{=}), and new
values are appended to the array beginning at one greater than the array's
maximum index.
maximum index (for indexed arrays), or added as additional key-value pairs
in an associative array.
When applied to a string-valued variable, @var{value} is expanded and
appended to the variable's value.
@@ -2921,13 +2922,15 @@ is supplied.
@item readonly
@btindex readonly
@example
readonly [-apf] [@var{name}[=@var{value}]] @dots{}
readonly [-aApf] [@var{name}[=@var{value}]] @dots{}
@end example
Mark each @var{name} as readonly.
The values of these names may not be changed by subsequent assignment.
If the @option{-f} option is supplied, each @var{name} refers to a shell
function.
The @option{-a} option means each @var{name} refers to an array variable.
The @option{-a} option means each @var{name} refers to an indexed
array variable; the @option{-A} option means each @var{name} refers
to an associative array variable.
If no @var{name} arguments are given, or if the @option{-p}
option is supplied, a list of all readonly names is printed.
The @option{-p} option causes output to be displayed in a format that
@@ -3318,7 +3321,7 @@ zero if @var{command} is found, and non-zero if not.
@item declare
@btindex declare
@example
declare [-afFirtx] [-p] [@var{name}[=@var{value}] @dots{}]
declare [-aAfFirtx] [-p] [@var{name}[=@var{value}] @dots{}]
@end example
Declare variables and give them attributes. If no @var{name}s
@@ -3347,7 +3350,10 @@ the specified attributes or to give variables attributes:
@table @code
@item -a
Each @var{name} is an array variable (@pxref{Arrays}).
Each @var{name} is an indexed array variable (@pxref{Arrays}).
@item -A
Each @var{name} is an associative array variable (@pxref{Arrays}).
@item -f
Use function names only.
@@ -3664,6 +3670,7 @@ the decimal point.
This option is only effective if @code{read} is reading input from a
terminal, pipe, or other special file; it has no effect when reading
from regular files.
The exit status is greater than 128 if the timeout is exceeded.
@item -u @var{fd}
Read input from file descriptor @var{fd}.
@@ -4517,6 +4524,13 @@ Expands to the process id of the current Bash process.
This differs from @code{$$} under certain circumstances, such as subshells
that do not require Bash to be re-initialized.
@item BASH_ALIASES
An associative array variable whose members correspond to the internal
list of aliases as maintained by the @code{alias} builtin
(@pxref{Bourne Shell Builtins}).
Elements added to this array appear in the alias list; unsetting array
elements cause aliases to be removed from the alias list.
@item BASH_ARGC
An array variable whose values are the number of parameters in each
frame of the current bash execution call stack. The number of
@@ -4540,6 +4554,13 @@ The shell sets @code{BASH_ARGV} only when in extended debugging mode
for a description of the @code{extdebug} option to the @code{shopt}
builtin).
@item BASH_CMDS
An associative array variable whose members correspond to the internal
hash table of commands as maintained by the @code{hash} builtin
(@pxref{Bourne Shell Builtins}).
Elements are to this array appear in the hash table; unsetting array
elements cause commands to be removed from the hash table.
@item BASH_COMMAND
The command currently being executed or about to be executed, unless the
shell is executing a command as the result of a trap,
@@ -5806,14 +5827,18 @@ For almost every purpose, shell functions are preferred over aliases.
@section Arrays
@cindex arrays
Bash provides one-dimensional array variables. Any variable may be used as
an array; the @code{declare} builtin will explicitly declare an array.
Bash provides one-dimensional indexed and associative array variables.
Any variable may be used as an array; the @code{declare} builtin will
explicitly declare an array.
There is no maximum
limit on the size of an array, nor any requirement that members
be indexed or assigned contiguously. Arrays are zero-based.
be indexed or assigned contiguously.
Indexed arrays are referenced using integers (including arithmetic
expressions (@pxref{Shell Arithmetic}) and are zero-based;
associative arrays use arbitrary strings.
An array is created automatically if any variable is assigned to using
the syntax
An indexed array is created automatically if any variable is assigned to
using the syntax
@example
name[@var{subscript}]=@var{value}
@end example
@@ -5836,16 +5861,25 @@ specified for an array variable using the @code{declare} and
@code{readonly} builtins. Each attribute applies to all members of
an array.
Associative arrays are created using
@example
declare -A @var{name}.
@end example
Arrays are assigned to using compound assignments of the form
@example
name=(value@var{1} @dots{} value@var{n})
@end example
@noindent
where each
@var{value} is of the form @code{[[@var{subscript}]=]}@var{string}. If
@var{value} is of the form @code{[[@var{subscript}]=]}@var{string}.
When using indexed arrays, if
the optional subscript is supplied, that index is assigned to;
otherwise the index of the element assigned is the last index assigned
to by the statement plus one. Indexing starts at zero.
When assigning to an associative array, the subscript is required.
This syntax is also accepted by the @code{declare}
builtin. Individual array elements may be assigned to using the
@code{name[}@var{subscript}@code{]=}@var{value} syntax introduced above.
@@ -5874,7 +5908,7 @@ expansion of the special parameters @samp{@@} and @samp{*}.
If @var{subscript} is @samp{@@} or
@samp{*}, the expansion is the number of elements in the array.
Referencing an array variable without a subscript is equivalent to
referencing element zero.
referencing with a subscript of 0.
The @code{unset} builtin is used to destroy arrays.
@code{unset} @var{name}[@var{subscript}]
@@ -5886,9 +5920,9 @@ entire array. A subscript of @samp{*} or @samp{@@} also removes the
entire array.
The @code{declare}, @code{local}, and @code{readonly}
builtins each accept a @option{-a}
option to specify an array. The @code{read}
builtin accepts a @option{-a}
builtins each accept a @option{-a} option to specify an indexed
array and a @option{-A} option to specify an associative array.
The @code{read} builtin accepts a @option{-a}
option to assign a list of words read from the standard input
to an array, and can read values from the standard input into
individual array elements. The @code{set} and @code{declare}
@@ -7019,6 +7053,14 @@ Include @code{csh}-like brace expansion
( @code{b@{a,b@}c} @expansion{} @code{bac bbc} ).
See @ref{Brace Expansion}, for a complete description.
@item --enable-casemod-attributes
Include support for case-modifying attributes in the @code{declare} builtin
and assignment statements. Variables with the @var{uppercase} attribute,
for example, will have their values converted to uppercase upon assignment.
@item --enable-casemod-expansion
Include support for case-modifying word expansions.
@item --enable-command-timing
Include support for recognizing @code{time} as a reserved word and for
displaying timing statistics for the pipeline following @code{time}
+2 -2
View File
@@ -2,9 +2,9 @@
Copyright (C) 1988-2008 Free Software Foundation, Inc.
@end ignore
@set LASTCHANGE Mon Jun 2 20:32:28 EDT 2008
@set LASTCHANGE Sun Jun 29 22:41:25 EDT 2008
@set EDITION 4.0
@set VERSION 4.0
@set UPDATED 2 June 2008
@set UPDATED 29 June 2008
@set UPDATED-MONTH June 2008
+3 -3
View File
@@ -2,9 +2,9 @@
Copyright (C) 1988-2008 Free Software Foundation, Inc.
@end ignore
@set LASTCHANGE Sun May 25 10:48:26 EDT 2008
@set LASTCHANGE Thu Jun 26 10:59:10 EDT 2008
@set EDITION 4.0
@set VERSION 4.0
@set UPDATED 25 May 2008
@set UPDATED-MONTH May 2008
@set UPDATED 26 June 2008
@set UPDATED-MONTH June 2008
+30
View File
@@ -506,8 +506,15 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
volatile int last_pid;
volatile int save_line_number;
#if 0
if (command == 0 || breaking || continuing || read_but_dont_execute)
return (EXECUTION_SUCCESS);
#else
if (breaking || continuing)
return (last_command_exit_value);
if (command == 0 || read_but_dont_execute)
return (EXECUTION_SUCCESS);
#endif
QUIT;
run_pending_traps ();
@@ -2735,11 +2742,13 @@ fix_assignment_words (words)
{
WORD_LIST *w;
struct builtin *b;
int assoc;
if (words == 0)
return;
b = 0;
assoc = 0;
for (w = words; w; w = w->next)
if (w->word->flags & W_ASSIGNMENT)
@@ -2753,7 +2762,28 @@ fix_assignment_words (words)
words->word->flags |= W_ASSNBLTIN;
}
w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP|W_ASSIGNARG);
#if defined (ARRAY_VARS)
if (assoc)
w->word->flags |= W_ASSIGNASSOC;
#endif
}
#if defined (ARRAY_VARS)
/* Note that we saw an associative array option to a builtin that takes
assignment statements. This is a bit of a kludge. */
else if (w->word->word[0] == '-' && strchr (w->word->word, 'A'))
{
if (b == 0)
{
b = builtin_address_internal (words->word->word, 0);
if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0)
return;
else if (b && (b->flags & ASSIGNMENT_BUILTIN))
words->word->flags |= W_ASSNBLTIN;
}
if (words->word->flags & W_ASSNBLTIN)
assoc = 1;
}
#endif
}
/* Return 1 if the file found by searching $PATH for PATHNAME, defaulting
+34 -4
View File
@@ -2292,10 +2292,17 @@ execute_case_command (case_command)
if (match)
{
if (clauses->action && ignore_return)
clauses->action->flags |= CMD_IGNORE_RETURN;
retval = execute_command (clauses->action);
EXIT_CASE ();
do
{
if (clauses->action && ignore_return)
clauses->action->flags |= CMD_IGNORE_RETURN;
retval = execute_command (clauses->action);
}
while ((clauses->flags & CASEPAT_FALLTHROUGH) && (clauses = clauses->next));
if ((clauses->flags & CASEPAT_TESTNEXT) == 0)
EXIT_CASE ();
else
break;
}
QUIT;
@@ -2728,11 +2735,13 @@ fix_assignment_words (words)
{
WORD_LIST *w;
struct builtin *b;
int assoc;
if (words == 0)
return;
b = 0;
assoc = 0;
for (w = words; w; w = w->next)
if (w->word->flags & W_ASSIGNMENT)
@@ -2746,7 +2755,28 @@ fix_assignment_words (words)
words->word->flags |= W_ASSNBLTIN;
}
w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP|W_ASSIGNARG);
#if defined (ARRAY_VARS)
if (assoc)
w->word->flags |= W_ASSIGNASSOC;
#endif
}
#if defined (ARRAY_VARS)
/* Note that we saw an associative array option to a builtin that takes
assignment statements. This is a bit of a kludge. */
else if (w->word->word[0] == '-' && strchr (w->word->word, 'A'))
{
if (b == 0)
{
b = builtin_address_internal (words->word->word, 0);
if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0)
return;
else if (b && (b->flags & ASSIGNMENT_BUILTIN))
words->word->flags |= W_ASSNBLTIN;
}
if (words->word->flags & W_ASSNBLTIN)
assoc = 1;
}
#endif
}
/* Return 1 if the file found by searching $PATH for PATHNAME, defaulting
+22 -1
View File
@@ -1,6 +1,6 @@
/* execute_cmd.h - functions from execute_cmd.c. */
/* Copyright (C) 1993 Free Software Foundation, Inc.
/* Copyright (C) 1993-2008 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -35,6 +35,27 @@ extern void dispose_exec_redirects __P ((void));
extern int execute_shell_function __P((SHELL_VAR *, WORD_LIST *));
extern struct coproc *getcoprocbypid __P((pid_t));
extern struct coproc *getcoprocbyname __P((const char *));
extern void coproc_init __P((struct coproc *));
extern struct coproc *coproc_alloc __P((char *, pid_t));
extern void coproc_dispose __P((struct coproc *));
extern void coproc_close __P((struct coproc *));
extern void coproc_rclose __P((struct coproc *, int));
extern void coproc_wclose __P((struct coproc *, int));
extern void coproc_fdclose __P((struct coproc *, int));
extern void coproc_fdchk __P((struct coproc *, int));
extern void coproc_pidchk __P((pid_t));
extern void coproc_fdsave __P((struct coproc *));
extern void coproc_fdrestore __P((struct coproc *));
extern void coproc_setvars __P((struct coproc *));
extern void coproc_unsetvars __P((struct coproc *));
#if defined (PROCESS_SUBSTITUTION)
extern void close_all_files __P((void));
#endif
+64 -39
View File
@@ -1912,11 +1912,33 @@ history list.
GNU Readline library. This application interactively allows users
to manipulate files and their modes. */
#include <stdio.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
#include <sys/file.h>
#ifdef HAVE_SYS_FILE_H
# include <sys/file.h>
#endif
#include <sys/stat.h>
#include <sys/errno.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#if defined (HAVE_STRING_H)
# include <string.h>
#else /* !HAVE_STRING_H */
# include <strings.h>
#endif /* !HAVE_STRING_H */
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include <readline/readline.h>
#include <readline/history.h>
@@ -1924,15 +1946,15 @@ history list.
extern char *xmalloc ();
/* The names of functions that actually do the manipulation. */
int com_list __P((char *));
int com_view __P((char *));
int com_rename __P((char *));
int com_stat __P((char *));
int com_pwd __P((char *));
int com_delete __P((char *));
int com_help __P((char *));
int com_cd __P((char *));
int com_quit __P((char *));
int com_list PARAMS((char *));
int com_view PARAMS((char *));
int com_rename PARAMS((char *));
int com_stat PARAMS((char *));
int com_pwd PARAMS((char *));
int com_delete PARAMS((char *));
int com_help PARAMS((char *));
int com_cd PARAMS((char *));
int com_quit PARAMS((char *));
/* A structure which contains information on the commands this program
can understand. */
@@ -1965,12 +1987,12 @@ COMMAND *find_command ();
/* The name of this program, as taken from argv[0]. */
char *progname;
/* When non-zero, this means the user is done using this program. */
/* When non-zero, this global means the user is done using this program. */
int done;
char *
dupstr (s)
int s;
char *s;
@{
char *r;
@@ -2095,12 +2117,12 @@ stripwhite (string)
/* */
/* **************************************************************** */
char *command_generator __P((const char *, int));
char **fileman_completion __P((const char *, int, int));
char *command_generator PARAMS((const char *, int));
char **fileman_completion PARAMS((const char *, int, int));
/* Tell the GNU Readline library how to complete. We want to try to
complete on command names if this is the first word in the line, or
on filenames if not. */
/* Tell the GNU Readline library how to complete. We want to try to complete
on command names if this is the first word in the line, or on filenames
if not. */
initialize_readline ()
@{
/* Allow conditional parsing of the ~/.inputrc file. */
@@ -2110,11 +2132,11 @@ initialize_readline ()
rl_attempted_completion_function = fileman_completion;
@}
/* Attempt to complete on the contents of TEXT. START and END
bound the region of rl_line_buffer that contains the word to
complete. TEXT is the word to complete. We can use the entire
contents of rl_line_buffer in case we want to do some simple
parsing. Returnthe array of matches, or NULL if there aren't any. */
/* Attempt to complete on the contents of TEXT. START and END bound the
region of rl_line_buffer that contains the word to complete. TEXT is
the word to complete. We can use the entire contents of rl_line_buffer
in case we want to do some simple parsing. Return the array of matches,
or NULL if there aren't any. */
char **
fileman_completion (text, start, end)
const char *text;
@@ -2133,9 +2155,9 @@ fileman_completion (text, start, end)
return (matches);
@}
/* Generator function for command completion. STATE lets us
know whether to start from scratch; without any state
(i.e. STATE == 0), then we start at the top of the list. */
/* Generator function for command completion. STATE lets us know whether
to start from scratch; without any state (i.e. STATE == 0), then we
start at the top of the list. */
char *
command_generator (text, state)
const char *text;
@@ -2144,17 +2166,16 @@ command_generator (text, state)
static int list_index, len;
char *name;
/* If this is a new word to complete, initialize now. This
includes saving the length of TEXT for efficiency, and
initializing the index variable to 0. */
/* If this is a new word to complete, initialize now. This includes
saving the length of TEXT for efficiency, and initializing the index
variable to 0. */
if (!state)
@{
list_index = 0;
len = strlen (text);
@}
/* Return the next name which partially matches from the
command list. */
/* Return the next name which partially matches from the command list. */
while (name = commands[list_index].name)
@{
list_index++;
@@ -2194,7 +2215,12 @@ com_view (arg)
if (!valid_argument ("view", arg))
return 1;
#if defined (__MSDOS__)
/* more.com doesn't grok slashes in pathnames */
sprintf (syscom, "less %s", arg);
#else
sprintf (syscom, "more %s", arg);
#endif
return (system (syscom));
@}
@@ -2221,7 +2247,8 @@ com_stat (arg)
printf ("Statistics for `%s':\n", arg);
printf ("%s has %d link%s, and is %d byte%s in length.\n", arg,
printf ("%s has %d link%s, and is %d byte%s in length.\n",
arg,
finfo.st_nlink,
(finfo.st_nlink == 1) ? "" : "s",
finfo.st_size,
@@ -2310,8 +2337,7 @@ com_pwd (ignore)
return 0;
@}
/* The user wishes to quit using this program. Just set DONE
non-zero. */
/* The user wishes to quit using this program. Just set DONE non-zero. */
com_quit (arg)
char *arg;
@{
@@ -2324,13 +2350,12 @@ too_dangerous (caller)
char *caller;
@{
fprintf (stderr,
"%s: Too dangerous for me to distribute.\n",
"%s: Too dangerous for me to distribute. Write it yourself.\n",
caller);
fprintf (stderr, "Write it yourself.\n");
@}
/* Return non-zero if ARG is a valid argument for CALLER,
else print an error message and return zero. */
/* Return non-zero if ARG is a valid argument for CALLER, else print
an error message and return zero. */
int
valid_argument (caller, arg)
char *caller, *arg;
+2 -1
View File
@@ -553,8 +553,9 @@ make_simple_command (element, command)
the redirectee.word with the new input text. If <<- is on,
then remove leading TABS from each line. */
void
make_here_document (temp)
make_here_document (temp, lineno)
REDIRECT *temp;
int lineno;
{
int kill_leading, redir_len;
char *redir_word, *document, *full_line;
+4 -2
View File
@@ -1,7 +1,7 @@
/* make_cmd.c -- Functions for making instances of the various
parser constructs. */
/* Copyright (C) 1989-2007 Free Software Foundation, Inc.
/* Copyright (C) 1989-2008 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -553,8 +553,9 @@ make_simple_command (element, command)
the redirectee.word with the new input text. If <<- is on,
then remove leading TABS from each line. */
void
make_here_document (temp)
make_here_document (temp, lineno)
REDIRECT *temp;
int lineno;
{
int kill_leading, redir_len;
char *redir_word, *document, *full_line;
@@ -690,6 +691,7 @@ make_redirection (source, instruction, dest_and_filename)
break;
case r_appending_to: /* >>foo */
case r_append_err_and_out: /* &>> filename */
temp->flags = O_APPEND | O_WRONLY | O_CREAT;
break;
+1 -1
View File
@@ -46,7 +46,7 @@ extern COMMAND *make_while_command __P((COMMAND *, COMMAND *));
extern COMMAND *make_until_command __P((COMMAND *, COMMAND *));
extern COMMAND *make_bare_simple_command __P((void));
extern COMMAND *make_simple_command __P((ELEMENT, COMMAND *));
extern void make_here_document __P((REDIRECT *));
extern void make_here_document __P((REDIRECT *, int));
extern REDIRECT *make_redirection __P((int, enum r_instruction, REDIRECTEE));
extern COMMAND *make_function_def __P((WORD_DESC *, COMMAND *, int, int));
extern COMMAND *clean_simple_command __P((COMMAND *));
+69
View File
@@ -0,0 +1,69 @@
/* make_cmd.h -- Declarations of functions found in make_cmd.c */
/* Copyright (C) 1993-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#if !defined (_MAKE_CMD_H_)
#define _MAKE_CMD_H_
#include "stdc.h"
extern void cmd_init __P((void));
extern WORD_DESC *alloc_word_desc __P((void));
extern WORD_DESC *make_bare_word __P((const char *));
extern WORD_DESC *make_word_flags __P((WORD_DESC *, const char *));
extern WORD_DESC *make_word __P((const char *));
extern WORD_DESC *make_word_from_token __P((int));
extern WORD_LIST *make_word_list __P((WORD_DESC *, WORD_LIST *));
#define add_string_to_list(s, l) make_word_list (make_word(s), (l))
extern COMMAND *make_command __P((enum command_type, SIMPLE_COM *));
extern COMMAND *command_connect __P((COMMAND *, COMMAND *, int));
extern COMMAND *make_for_command __P((WORD_DESC *, WORD_LIST *, COMMAND *, int));
extern COMMAND *make_group_command __P((COMMAND *));
extern COMMAND *make_case_command __P((WORD_DESC *, PATTERN_LIST *, int));
extern PATTERN_LIST *make_pattern_list __P((WORD_LIST *, COMMAND *));
extern COMMAND *make_if_command __P((COMMAND *, COMMAND *, COMMAND *));
extern COMMAND *make_while_command __P((COMMAND *, COMMAND *));
extern COMMAND *make_until_command __P((COMMAND *, COMMAND *));
extern COMMAND *make_bare_simple_command __P((void));
extern COMMAND *make_simple_command __P((ELEMENT, COMMAND *));
extern void make_here_document __P((REDIRECT *));
extern REDIRECT *make_redirection __P((int, enum r_instruction, REDIRECTEE));
extern COMMAND *make_function_def __P((WORD_DESC *, COMMAND *, int, int));
extern COMMAND *clean_simple_command __P((COMMAND *));
extern COMMAND *make_arith_command __P((WORD_LIST *));
extern COMMAND *make_select_command __P((WORD_DESC *, WORD_LIST *, COMMAND *, int));
#if defined (COND_COMMAND)
extern COND_COM *make_cond_node __P((int, WORD_DESC *, COND_COM *, COND_COM *));
extern COMMAND *make_cond_command __P((COND_COM *));
#endif
extern COMMAND *make_arith_for_command __P((WORD_LIST *, COMMAND *, int));
extern COMMAND *make_subshell_command __P((COMMAND *));
extern COMMAND *connect_async_list __P((COMMAND *, COMMAND *, int));
#endif /* !_MAKE_CMD_H */
+7 -3
View File
@@ -2304,7 +2304,7 @@ gather_here_documents ()
int r = 0;
while (need_here_doc)
{
make_here_document (redir_stack[r++]);
make_here_document (redir_stack[r++], line_number);
need_here_doc--;
}
}
@@ -4142,8 +4142,12 @@ read_token_word (character)
}
#if defined (ARRAY_VARS)
/* Identify possible array subscript assignment; match [...] */
else if MBTEST(character == '[' && token_index > 0 && assignment_acceptable (last_read_token) && token_is_ident (token, token_index)) /* ] */
/* Identify possible array subscript assignment; match [...]. If
parser_state&PST_COMPASSIGN, we need to parse [sub]=words treating
`sub' as if it were enclosed in double quotes. */
else if MBTEST(character == '[' && /* ] */
((token_index > 0 && assignment_acceptable (last_read_token) && token_is_ident (token, token_index)) ||
(token_index == 0 && (parser_state&PST_COMPASSIGN))))
{
ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0);
if (ttok == &matched_pair_error)
+5 -4
View File
@@ -766,12 +766,13 @@ case_command: CASE WORD newline_list IN newline_list ESAC
function_def: WORD '(' ')' newline_list function_body
{ $$ = make_function_def ($1, $5, function_dstart, function_bstart); }
| FUNCTION WORD newline_list function_body
{ $$ = make_function_def ($2, $4, function_dstart, function_bstart); }
| FUNCTION WORD '(' ')' newline_list function_body
{ $$ = make_function_def ($2, $6, function_dstart, function_bstart); }
;
| FUNCTION WORD newline_list function_body
{ $$ = make_function_def ($2, $4, function_dstart, function_bstart); }
;
function_body: shell_command
{ $$ = $1; }
@@ -2303,7 +2304,7 @@ gather_here_documents ()
int r = 0;
while (need_here_doc)
{
make_here_document (redir_stack[r++]);
make_here_document (redir_stack[r++], line_number);
need_here_doc--;
}
}
+105 -31
View File
@@ -244,7 +244,7 @@ static char *variable_remove_pattern __P((char *, char *, int, int));
static char *list_remove_pattern __P((WORD_LIST *, char *, int, int, int));
static char *parameter_list_remove_pattern __P((int, char *, int, int));
#ifdef ARRAY_VARS
static char *array_remove_pattern __P((ARRAY *, char *, int, char *, int));
static char *array_remove_pattern __P((SHELL_VAR *, char *, int, char *, int));
#endif
static char *parameter_brace_remove_pattern __P((char *, char *, char *, int, int));
@@ -292,6 +292,9 @@ static WORD_LIST *glob_expand_word_list __P((WORD_LIST *, int));
#ifdef BRACE_EXPANSION
static WORD_LIST *brace_expand_word_list __P((WORD_LIST *, int));
#endif
#if defined (ARRAY_VARS)
static int make_internal_declare __P((char *, char *));
#endif
static WORD_LIST *shell_expand_word_list __P((WORD_LIST *, int));
static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int));
@@ -2345,8 +2348,8 @@ do_compound_assignment (name, value, flags)
if (mklocal && variable_context)
{
list = expand_compound_array_assignment (value, flags);
v = find_variable (name);
list = expand_compound_array_assignment (v, value, flags);
if (v == 0 || array_p (v) == 0 || v->context != variable_context)
v = make_local_array_variable (name);
assign_compound_array_list (v, list, flags);
@@ -4053,13 +4056,15 @@ parameter_list_remove_pattern (itype, pattern, patspec, quoted)
#if defined (ARRAY_VARS)
static char *
array_remove_pattern (a, pattern, patspec, varname, quoted)
ARRAY *a;
array_remove_pattern (var, pattern, patspec, varname, quoted)
SHELL_VAR *var;
char *pattern;
int patspec;
char *varname; /* so we can figure out how it's indexed */
int quoted;
{
ARRAY *a;
HASH_TABLE *h;
int itype;
char *ret;
WORD_LIST *list;
@@ -4069,7 +4074,10 @@ array_remove_pattern (a, pattern, patspec, varname, quoted)
v = array_variable_part (varname, &ret, 0);
itype = ret[0];
list = array_to_word_list (a);
a = (v && array_p (v)) ? array_cell (v) : 0;
h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
if (list == 0)
return ((char *)NULL);
ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
@@ -4129,7 +4137,7 @@ parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted)
break;
#if defined (ARRAY_VARS)
case VT_ARRAYVAR:
temp1 = array_remove_pattern (array_cell (v), pattern, patspec, varname, quoted);
temp1 = array_remove_pattern (v, pattern, patspec, varname, quoted);
if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
{
val = quote_escapes (temp1);
@@ -4919,6 +4927,7 @@ array_length_reference (s)
{
int len;
arrayind_t ind;
char *akey;
char *t, c;
ARRAY *array;
SHELL_VAR *var;
@@ -4927,7 +4936,7 @@ array_length_reference (s)
/* If unbound variables should generate an error, report one and return
failure. */
if ((var == 0 || array_p (var) == 0) && unbound_vars_is_error)
if ((var == 0 || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
{
c = *--t;
*t = '\0';
@@ -4945,19 +4954,40 @@ array_length_reference (s)
array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
return (array_p (var) ? array_num_elements (array) : 1);
ind = array_expand_index (t, len);
if (ind < 0)
{
err_badarraysub (t);
return (-1);
if (assoc_p (var))
return (assoc_num_elements (assoc_cell (var)));
else if (array_p (var))
return (array_num_elements (array));
else
return 1;
}
if (array_p (var))
t = array_reference (array, ind);
if (assoc_p (var))
{
t[len - 1] = '\0';
akey = expand_assignment_string_to_string (t, 0); /* [ */
t[len - 1] = ']';
if (akey == 0 || *akey == 0)
{
err_badarraysub (t);
return (-1);
}
t = assoc_reference (assoc_cell (var), akey);
}
else
t = (ind == 0) ? value_cell (var) : (char *)NULL;
{
ind = array_expand_index (t, len);
if (ind < 0)
{
err_badarraysub (t);
return (-1);
}
if (array_p (var))
t = array_reference (array, ind);
else
t = (ind == 0) ? value_cell (var) : (char *)NULL;
}
len = STRLEN (t);
return (len);
@@ -5102,7 +5132,12 @@ parameter_brace_expand_word (name, var_is_special, quoted)
if (var_isset (var) && invisible_p (var) == 0)
{
#if defined (ARRAY_VARS)
temp = array_p (var) ? array_reference (array_cell (var), 0) : value_cell (var);
if (assoc_p (var))
temp = assoc_reference (assoc_cell (var), "0");
else if (array_p (var))
temp = array_reference (array_cell (var), 0);
else
temp = value_cell (var);
#else
temp = value_cell (var);
#endif
@@ -5375,9 +5410,12 @@ parameter_brace_expand_length (name)
FREE (t);
}
#if defined (ARRAY_VARS)
else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && array_p (var))
else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
{
t = array_reference (array_cell (var), 0);
if (assoc_p (var))
t = assoc_reference (assoc_cell (var), "0");
else
t = array_reference (array_cell (var), 0);
number = MB_STRLEN (t);
}
#endif
@@ -5591,14 +5629,14 @@ get_var_and_type (varname, value, quoted, varp, valp)
if (valid_array_reference (varname))
{
v = array_variable_part (varname, &temp, (int *)0);
if (v && array_p (v))
if (v && (array_p (v) || assoc_p (v)))
{ /* [ */
if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')
{
vtype = VT_ARRAYVAR;
if (temp[0] == '*')
vtype |= VT_STARSUB;
*valp = (char *)array_cell (v);
*valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v);
}
else
{
@@ -5617,13 +5655,17 @@ get_var_and_type (varname, value, quoted, varp, valp)
*valp = dequote_escapes (value);
}
else
return -1;
{
vtype = VT_ARRAYMEMBER;
*varp = v;
*valp = array_value (varname, 1, (int *)NULL);
}
}
else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && array_p (v))
else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
{
vtype = VT_ARRAYMEMBER;
*varp = v;
*valp = array_reference (array_cell (v), 0);
*valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
}
else
#endif
@@ -5744,10 +5786,13 @@ parameter_brace_substring (varname, value, substr, quoted)
break;
#if defined (ARRAY_VARS)
case VT_ARRAYVAR:
if (assoc_p (v))
tt = (char *)NULL;
else
/* We want E2 to be the number of elements desired (arrays can be sparse,
so verify_substring_values just returns the numbers specified and we
rely on array_subrange to understand how to deal with them). */
temp = array_subrange (array_cell (v), e1, e2, starsub, quoted);
temp = array_subrange (array_cell (v), e1, e2, starsub, quoted);
/* array_subrange now calls array_quote_escapes as appropriate, so the
caller no longer needs to. */
break;
@@ -6022,10 +6067,11 @@ parameter_brace_patsub (varname, value, patsub, quoted)
break;
#if defined (ARRAY_VARS)
case VT_ARRAYVAR:
temp = array_patsub (array_cell (v), p, rep, mflags);
temp = assoc_p (v) ? assoc_patsub (assoc_cell (v), p, rep, mflags)
: array_patsub (array_cell (v), p, rep, mflags);
/* Don't call quote_escapes anymore; array_patsub calls
array_quote_escapes as appropriate before adding the
space separators. */
space separators; ditto for assoc_patsub. */
break;
#endif
}
@@ -6289,7 +6335,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
FREE (x);
if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == ']')
{
temp = array_keys (temp1, quoted);
temp = array_keys (temp1, quoted); /* handles assoc vars too */
if (x1[0] == '@')
{
if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
@@ -6844,9 +6890,10 @@ comsub:
if (var && invisible_p (var) == 0 && var_isset (var))
{
#if defined (ARRAY_VARS)
if (array_p (var))
if (assoc_p (var) || array_p (var))
{
temp = array_reference (array_cell (var), 0);
temp = array_p (var) ? array_reference (array_cell (var), 0)
: assoc_reference (assoc_cell (var), "0");
if (temp)
temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
? quote_string (temp)
@@ -8159,6 +8206,30 @@ brace_expand_word_list (tlist, eflags)
}
#endif
#if defined (ARRAY_VARS)
/* Take WORD, a compound associative array assignment, and internally run
'declare -A w', where W is the variable name portion of WORD. */
static int
make_internal_declare (word, option)
char *word;
char *option;
{
int t;
WORD_LIST *wl;
WORD_DESC *w;
w = make_word (word);
t = assignment (w->word, 0);
w->word[t] = '\0';
wl = make_word_list (w, (WORD_LIST *)NULL);
wl = make_word_list (make_word (option), wl);
return (declare_builtin (wl));
}
#endif
static WORD_LIST *
shell_expand_word_list (tlist, eflags)
WORD_LIST *tlist;
@@ -8187,6 +8258,9 @@ shell_expand_word_list (tlist, eflags)
{
int t;
if (tlist->word->flags & W_ASSIGNASSOC)
make_internal_declare (tlist->word->word, "-A");
t = do_word_assignment (tlist->word);
if (t == 0)
{
@@ -8197,7 +8271,7 @@ shell_expand_word_list (tlist, eflags)
/* Now transform the word as ksh93 appears to do and go on */
t = assignment (tlist->word->word, 0);
tlist->word->word[t] = '\0';
tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG);
tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC);
}
#endif
+105 -45
View File
@@ -244,7 +244,7 @@ static char *variable_remove_pattern __P((char *, char *, int, int));
static char *list_remove_pattern __P((WORD_LIST *, char *, int, int, int));
static char *parameter_list_remove_pattern __P((int, char *, int, int));
#ifdef ARRAY_VARS
static char *array_remove_pattern __P((ARRAY *, char *, int, char *, int));
static char *array_remove_pattern __P((SHELL_VAR *, char *, int, char *, int));
#endif
static char *parameter_brace_remove_pattern __P((char *, char *, char *, int, int));
@@ -292,6 +292,9 @@ static WORD_LIST *glob_expand_word_list __P((WORD_LIST *, int));
#ifdef BRACE_EXPANSION
static WORD_LIST *brace_expand_word_list __P((WORD_LIST *, int));
#endif
#if defined (ARRAY_VARS)
static int make_internal_declare __P((char *, char *));
#endif
static WORD_LIST *shell_expand_word_list __P((WORD_LIST *, int));
static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int));
@@ -2345,8 +2348,8 @@ do_compound_assignment (name, value, flags)
if (mklocal && variable_context)
{
list = expand_compound_array_assignment (value, flags);
v = find_variable (name);
list = expand_compound_array_assignment (v, value, flags);
if (v == 0 || array_p (v) == 0 || v->context != variable_context)
v = make_local_array_variable (name);
assign_compound_array_list (v, list, flags);
@@ -4028,20 +4031,7 @@ list_remove_pattern (list, pattern, patspec, itype, quoted)
}
l = REVERSE_LIST (new, WORD_LIST *);
#if 0
if (itype == '*' && (quoted & Q_DOUBLE_QUOTES))
tword = string_list_dollar_star (quote_list (l));
else if (itype == '*')
tword = string_list_dollar_star (l);
else if (itype == '@' && (quoted & Q_DOUBLE_QUOTES))
tword = string_list_dollar_at (l, quoted);
else if (itype == '@')
tword = string_list_dollar_star (l);
else
tword = string_list (l);
#else
tword = string_list_pos_params (itype, l, quoted);
#endif
dispose_words (l);
return (tword);
@@ -4066,13 +4056,15 @@ parameter_list_remove_pattern (itype, pattern, patspec, quoted)
#if defined (ARRAY_VARS)
static char *
array_remove_pattern (a, pattern, patspec, varname, quoted)
ARRAY *a;
array_remove_pattern (var, pattern, patspec, varname, quoted)
SHELL_VAR *var;
char *pattern;
int patspec;
char *varname; /* so we can figure out how it's indexed */
int quoted;
{
ARRAY *a;
HASH_TABLE *h;
int itype;
char *ret;
WORD_LIST *list;
@@ -4082,7 +4074,10 @@ array_remove_pattern (a, pattern, patspec, varname, quoted)
v = array_variable_part (varname, &ret, 0);
itype = ret[0];
list = array_to_word_list (a);
a = (v && array_p (v)) ? array_cell (v) : 0;
h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
if (list == 0)
return ((char *)NULL);
ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
@@ -4142,7 +4137,7 @@ parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted)
break;
#if defined (ARRAY_VARS)
case VT_ARRAYVAR:
temp1 = array_remove_pattern (array_cell (v), pattern, patspec, varname, quoted);
temp1 = array_remove_pattern (v, pattern, patspec, varname, quoted);
if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
{
val = quote_escapes (temp1);
@@ -4932,6 +4927,7 @@ array_length_reference (s)
{
int len;
arrayind_t ind;
char *akey;
char *t, c;
ARRAY *array;
SHELL_VAR *var;
@@ -4940,7 +4936,7 @@ array_length_reference (s)
/* If unbound variables should generate an error, report one and return
failure. */
if ((var == 0 || array_p (var) == 0) && unbound_vars_is_error)
if ((var == 0 || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
{
c = *--t;
*t = '\0';
@@ -4958,19 +4954,40 @@ array_length_reference (s)
array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
return (array_p (var) ? array_num_elements (array) : 1);
ind = array_expand_index (t, len);
if (ind < 0)
{
err_badarraysub (t);
return (-1);
if (assoc_p (var))
return (assoc_num_elements (assoc_cell (var)));
else if (array_p (var))
return (array_num_elements (array));
else
return 1;
}
if (array_p (var))
t = array_reference (array, ind);
if (assoc_p (var))
{
t[len - 1] = '\0';
akey = expand_assignment_string_to_string (t, 0); /* [ */
t[len - 1] = ']';
if (akey == 0 || *akey == 0)
{
err_badarraysub (t);
return (-1);
}
t = assoc_reference (assoc_cell (var), akey);
}
else
t = (ind == 0) ? value_cell (var) : (char *)NULL;
{
ind = array_expand_index (t, len);
if (ind < 0)
{
err_badarraysub (t);
return (-1);
}
if (array_p (var))
t = array_reference (array, ind);
else
t = (ind == 0) ? value_cell (var) : (char *)NULL;
}
len = STRLEN (t);
return (len);
@@ -5115,7 +5132,12 @@ parameter_brace_expand_word (name, var_is_special, quoted)
if (var_isset (var) && invisible_p (var) == 0)
{
#if defined (ARRAY_VARS)
temp = array_p (var) ? array_reference (array_cell (var), 0) : value_cell (var);
if (assoc_p (var))
temp = assoc_reference (assoc_cell (var), "0");
else if (array_p (var))
temp = array_reference (array_cell (var), 0);
else
temp = value_cell (var);
#else
temp = value_cell (var);
#endif
@@ -5388,9 +5410,12 @@ parameter_brace_expand_length (name)
FREE (t);
}
#if defined (ARRAY_VARS)
else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && array_p (var))
else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
{
t = array_reference (array_cell (var), 0);
if (assoc_p (var))
t = assoc_reference (assoc_cell (var), "0");
else
t = array_reference (array_cell (var), 0);
number = MB_STRLEN (t);
}
#endif
@@ -5604,14 +5629,14 @@ get_var_and_type (varname, value, quoted, varp, valp)
if (valid_array_reference (varname))
{
v = array_variable_part (varname, &temp, (int *)0);
if (v && array_p (v))
if (v && (array_p (v) || assoc_p (v)))
{ /* [ */
if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')
{
vtype = VT_ARRAYVAR;
if (temp[0] == '*')
vtype |= VT_STARSUB;
*valp = (char *)array_cell (v);
*valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v);
}
else
{
@@ -5630,13 +5655,17 @@ get_var_and_type (varname, value, quoted, varp, valp)
*valp = dequote_escapes (value);
}
else
return -1;
{
vtype = VT_ARRAYMEMBER;
*varp = v;
*valp = array_value (varname, 1, (int *)NULL);
}
}
else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && array_p (v))
else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
{
vtype = VT_ARRAYMEMBER;
*varp = v;
*valp = array_reference (array_cell (v), 0);
*valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
}
else
#endif
@@ -5757,10 +5786,13 @@ parameter_brace_substring (varname, value, substr, quoted)
break;
#if defined (ARRAY_VARS)
case VT_ARRAYVAR:
if (assoc_p (v))
tt = (char *)NULL;
else
/* We want E2 to be the number of elements desired (arrays can be sparse,
so verify_substring_values just returns the numbers specified and we
rely on array_subrange to understand how to deal with them). */
temp = array_subrange (array_cell (v), e1, e2, starsub, quoted);
temp = array_subrange (array_cell (v), e1, e2, starsub, quoted);
/* array_subrange now calls array_quote_escapes as appropriate, so the
caller no longer needs to. */
break;
@@ -6035,10 +6067,11 @@ parameter_brace_patsub (varname, value, patsub, quoted)
break;
#if defined (ARRAY_VARS)
case VT_ARRAYVAR:
temp = array_patsub (array_cell (v), p, rep, mflags);
temp = assoc_p (v) ? assoc_patsub (assoc_cell (v), p, rep, mflags)
: array_patsub (array_cell (v), p, rep, mflags);
/* Don't call quote_escapes anymore; array_patsub calls
array_quote_escapes as appropriate before adding the
space separators. */
space separators; ditto for assoc_patsub. */
break;
#endif
}
@@ -6302,7 +6335,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
FREE (x);
if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == ']')
{
temp = array_keys (temp1, quoted);
temp = array_keys (temp1, quoted); /* handles assoc vars too */
if (x1[0] == '@')
{
if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
@@ -6857,9 +6890,10 @@ comsub:
if (var && invisible_p (var) == 0 && var_isset (var))
{
#if defined (ARRAY_VARS)
if (array_p (var))
if (assoc_p (var) || array_p (var))
{
temp = array_reference (array_cell (var), 0);
temp = array_p (var) ? array_reference (array_cell (var), 0)
: assoc_reference (assoc_cell (var), "0");
if (temp)
temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
? quote_string (temp)
@@ -8172,6 +8206,30 @@ brace_expand_word_list (tlist, eflags)
}
#endif
#if defined (ARRAY_VARS)
/* Take WORD, a compound associative array assignment, and internally run
'declare -A w', where W is the variable name portion of WORD. */
static int
make_internal_declare (word, option)
char *word;
char *option;
{
int t;
WORD_LIST *wl;
WORD_DESC *w;
w = make_word (word);
t = assignment (w->word, 0);
w->word[t] = '\0';
wl = make_word_list (w, (WORD_LIST *)NULL);
wl = make_word_list (make_word (option), wl);
return (declare_builtin (wl));
}
#endif
static WORD_LIST *
shell_expand_word_list (tlist, eflags)
WORD_LIST *tlist;
@@ -8200,7 +8258,9 @@ shell_expand_word_list (tlist, eflags)
{
int t;
t = do_word_assignment (tlist->word);
if (tlist->word->flags & W_ASSIGNASSOC)
make_internal_declare (tlist->word->word, "-A");
if (t == 0)
{
last_command_exit_value = EXECUTION_FAILURE;
@@ -8210,7 +8270,7 @@ shell_expand_word_list (tlist, eflags)
/* Now transform the word as ksh93 appears to do and go on */
t = assignment (tlist->word->word, 0);
tlist->word->word[t] = '\0';
tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG);
tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC);
}
#endif
+1
View File
@@ -42,6 +42,7 @@
/* Flag values controlling how assignment statements are treated. */
#define ASS_APPEND 0x01
#define ASS_MKLOCAL 0x02
#define ASS_MKASSOC 0x04
/* Flags for the string extraction functions. */
#define SX_NOALLOC 0x01 /* just skip; don't return substring */
+8
View File
@@ -266,3 +266,11 @@ argv[1] = <element1 with spaces>
argv[2] = <element2 with spaces>
argv[1] = <element1 with spaces>
argv[2] = <element2 with spaces>
nord!olz
rdholz
rdholz
rdho
+1
View File
@@ -379,3 +379,4 @@ ${THIS_SH} ./array5.sub
# tests for post-bash-3.2 problems, most fixed in bash-3.2 patches
${THIS_SH} ./array6.sub
${THIS_SH} ./array7.sub
+381
View File
@@ -0,0 +1,381 @@
# this is needed so that the bad assignments (b[]=bcde, for example) do not
# cause fatal shell errors when in posix mode
set +o posix
set +a
# The calls to egrep -v are to filter out builtin array variables that are
# automatically set and possibly contain values that vary.
# first make sure we handle the basics
x=()
echo ${x[@]}
unset x
# this should be an error
test=(first & second)
echo $?
unset test
# make sure declare -a converts an existing variable to an array
unset a
a=abcde
declare -a a
echo ${a[0]}
unset a
a=abcde
a[2]=bdef
unset b
declare -a b[256]
unset c[2]
unset c[*]
a[1]=
_ENV=/bin/true
x=${_ENV[(_$-=0)+(_=1)-_${-%%*i*}]}
declare -r c[100]
echo ${a[0]} ${a[4]}
echo ${a[@]}
echo ${a[*]}
# this should print out values, too
declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
unset a[7]
echo ${a[*]}
unset a[4]
echo ${a[*]}
echo ${a}
echo "${a}"
echo $a
unset a[0]
echo ${a}
echo ${a[@]}
a[5]="hello world"
echo ${a[5]}
echo ${#a[5]}
echo ${#a[@]}
a[4+5/2]="test expression"
echo ${a[@]}
readonly a[5]
readonly a
# these two lines should output `declare' commands
readonly -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
declare -ar | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
# this line should output `readonly' commands, even for arrays
set -o posix
readonly -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
set +o posix
declare -a d='([1]="" [2]="bdef" [5]="hello world" "test")'
d[9]="ninth element"
declare -a e[10]=test # this works in post-bash-2.05 versions
declare -a e[10]='(test)'
pass=/etc/passwd
declare -a f='("${d[@]}")'
b=([0]=this [1]=is [2]=a [3]=test [4]="$PS1" [5]=$pass)
echo ${b[@]:2:3}
declare -pa | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
a[3]="this is a test"
b[]=bcde
b[*]=aaa
echo ${b[ ]}
c[-2]=4
echo ${c[-4]}
d[7]=(abdedfegeee)
d=([]=abcde [1]="test test" [*]=last [-65]=negative )
unset d[12]
unset e[*]
declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
ps1='hello'
unset ps1[2]
unset ${ps1[2]}
declare +a ps1
declare +a c
# the prompt should not print when using a here doc
read -p "array test: " -a rv <<!
this is a test of read using arrays
!
echo ${rv[0]} ${rv[4]}
echo ${rv[@]}
# the variable should be converted to an array when `read -a' is done
vv=1
read -a vv <<!
this is a test of arrays
!
echo ${vv[0]} ${vv[3]}
echo ${vv[@]}
unset vv
declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
export rv
#set
x[4]=bbb
x=abde
echo $x
echo ${x[0]}
echo ${x[4]}
echo efgh | ( read x[1] ; echo ${x[1]} )
echo wxyz | ( declare -a x ; read x ; echo $x ; echo ${x[0]} )
# Make sure that arrays can be used to save the positional paramters verbatim
set -- a 'b c' d 'e f g' h
ARGV=( [0]=$0 "$@" )
for z in "${ARGV[@]}"
do
echo "$z"
done
echo "$0"
for z in "$@"
do
echo "$z"
done
# do various pattern removal and length tests
XPATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:.:/sbin:/usr/sbin
xpath=( $( IFS=: ; echo $XPATH ) )
echo ${xpath[@]}
echo ${xpath[@]##*/}
echo ${xpath[0]##*/}
echo ${xpath[@]%%[!/]*}
echo ${xpath[0]%%[!/]*}
recho ${xpath##*/}
recho ${xpath%%[!/]*}
recho ${xpath[5]##*/}
recho ${xpath[5]%%[!/]*}
# let's try to make it a DOS-style path
zecho "${xpath[@]/\//\\}"
zecho "${xpath[@]//\//\\}"
zecho "${xpath[@]//[\/]/\\}"
# length of the first element of the array, since array without subscript
# is equivalent to referencing first element
echo ${#xpath} -- ${#xpath[0]}
# number of elements in the array
nelem=${#xpath[@]}
echo ${#xpath[@]} -- $nelem
# total length of all elements in the array, including space separators
xx="${xpath[*]}"
echo ${#xx}
# total length of all elements in the array
xx=$( IFS='' ; echo "${xpath[*]}" )
echo ${#xx}
unset xpath[nelem-1]
nelem=${#xpath[@]}
echo ${#xpath[@]} -- $nelem
# arrays and things that look like index assignments
array=(42 [1]=14 [2]=44)
array2=(grep [ 123 ] \*)
echo ${array[@]}
echo "${array2[@]}"
# arrays and implicit arithmetic evaluation
declare -i -a iarray
iarray=( 2+4 1+6 7+2 )
echo ${iarray[@]}
iarray[4]=4+1
echo ${iarray[@]}
# make sure assignment using the compound assignment syntax removes all
# of the old elements from the array value
barray=(old1 old2 old3 old4 old5)
barray=(new1 new2 new3)
echo "length = ${#barray[@]}"
echo "value = ${barray[*]}"
# make sure the array code behaves correctly with respect to unset variables
set -u
( echo ${#narray[4]} )
${THIS_SH} ./array1.sub
${THIS_SH} ./array2.sub
# some old bugs and ksh93 compatibility tests
${THIS_SH} ./array3.sub
# some compound assingment parsing problems that showed up in bash-3.1-release
${THIS_SH} ./array4.sub
set +u
cd /tmp
touch 1=bar
foo=([10]="bar")
echo ${foo[0]}
rm 1=bar
cd $OLDPWD
foo=(a b c d e f g)
echo ${foo[@]}
# quoted reserved words are ok
foo=(\for \case \if \then \else)
echo ${foo[@]}
# quoted metacharacters are ok
foo=( [1]='<>' [2]='<' [3]='>' [4]='!' )
echo ${foo[@]}
# numbers are just words when not in a redirection context
foo=( 12 14 16 18 20 )
echo ${foo[@]}
foo=( 4414758999202 )
echo ${foo[@]}
# this was a bug in all versions of bash 2.x up to and including bash-2.04
declare -a ddd=(aaa
bbb)
echo ${ddd[@]}
# errors until post-bash-2.05a; now reserved words are OK
foo=(a b c for case if then else)
foo=(for case if then else)
# errors
metas=( <> < > ! )
metas=( [1]=<> [2]=< [3]=> [4]=! )
# various expansions that didn't really work right until post-bash-2.04
foo='abc'
echo ${foo[0]} ${#foo[0]}
echo ${foo[1]} ${#foo[1]}
echo ${foo[@]} ${#foo[@]}
echo ${foo[*]} ${#foo[*]}
foo=''
echo ${foo[0]} ${#foo[0]}
echo ${foo[1]} ${#foo[1]}
echo ${foo[@]} ${#foo[@]}
echo ${foo[*]} ${#foo[*]}
# new expansions added after bash-2.05b
x[0]=zero
x[1]=one
x[4]=four
x[10]=ten
recho ${!x[@]}
recho "${!x[@]}"
recho ${!x[*]}
recho "${!x[*]}"
# sparse array tests for code fixed in bash-3.0
unset av
av[1]='one'
av[2]=''
av[3]=three
av[5]=five
av[7]=seven
echo include null element -- expect one
echo ${av[@]:1:2} # what happens when we include a null element?
echo include unset element -- expect three five
echo ${av[@]:3:2} # what happens when we include an unset element?
echo start at unset element -- expect five seven
echo ${av[@]:4:2} # what happens when we start at an unset element?
echo too many elements -- expect three five seven
echo ${av[@]:3:5} # how about too many elements?
echo positive offset - expect five seven
echo ${av[@]:5:2}
echo negative offset to unset element - expect seven
echo ${av[@]: -2:2}
echo positive offset 2 - expect seven
echo ${av[@]: 6:2}
echo negative offset 2 - expect seven
echo ${av[@]: -1:2}
echo out-of-range offset
echo ${av[@]:12}
# parsing problems and other inconsistencies not fixed until post bash-3.0
unset x
declare -a x=(')' $$)
[ ${x[1]} -eq $$ ] || echo bad
unset x
declare -a x=(a b c d e)
echo ${x[4]}
z=([1]=one [4]=four [7]=seven [10]=ten)
echo ${#z[@]}
echo ${!z[@]}
unset x
declare -a x=(a \'b c\')
echo "${x[1]}"
unset x
declare -a x=(a 'b c')
echo "${x[1]}"
unset x
declare -a x=($0)
[ "${x[@]}" = $0 ] || echo double expansion of \$0
declare -a x=(\$0)
echo "${x[@]}"
# tests for bash-3.1 problems
${THIS_SH} ./array5.sub
# tests for post-bash-3.2 problems, most fixed in bash-3.2 patches
${THIS_SH} ./array6.sub
+14
View File
@@ -0,0 +1,14 @@
# these didn't work in versions of bash before bash-4.0
LNAME=nordholz
echo ${LNAME[$(( 0 ))]//h/!}
echo ${LNAME[$(( 2 ))]//h/!}
echo ${LNAME[$(( 0 ))]##??}
echo ${LNAME[$(( 2 ))]##??}
echo ${LNAME[$(( 0 ))]:2}
echo ${LNAME[$(( 0 ))]:2:4}
echo ${LNAME[$(( 2 ))]:2}
echo ${LNAME[$(( 2 ))]:2:4}
+101
View File
@@ -0,0 +1,101 @@
declare -A BASH_ALIASES='()'
declare -A BASH_CMDS='()'
declare -A fluff='()'
declare -A BASH_ALIASES='()'
declare -A BASH_CMDS='()'
declare -A fluff='([bar]="two" [foo]="one" )'
declare -A fluff='([bar]="two" [foo]="one" )'
declare -A fluff='([bar]="two" )'
declare -A fluff='([bar]="newval" )'
./assoc.tests: line 24: chaff: four: must use subscript when assigning associative array
declare -A BASH_ALIASES='()'
declare -A BASH_CMDS='()'
declare -Ai chaff='([one]="10" [zero]="5" )'
declare -Ar waste='([version]="4.0-devel" [source]="./assoc.tests" [lineno]="26" [pid]="42134" )'
declare -A wheat='([one]="a" [zero]="0" [two]="b" [three]="c" )'
declare -A chaff='([one]="10" [hello world]="flip" [zero]="5" )'
./assoc.tests: line 36: unset: waste: cannot unset: readonly variable
./assoc.tests: line 37: chaff[*]: bad array subscript
./assoc.tests: line 38: [*]=12: invalid associative array key
declare -A chaff='([one]="a" [hello world]="flip" )'
flip
argv[1] = <a>
argv[2] = <flip>
argv[3] = <multiple>
argv[4] = <words>
argv[1] = <a>
argv[2] = <flip>
argv[3] = <multiple words>
argv[1] = <a>
argv[2] = <flip>
argv[3] = <multiple>
argv[4] = <words>
argv[1] = <a flip multiple words>
./assoc.tests: line 55: declare: chaff: cannot destroy array variables in this way
./assoc.tests: line 57: chaff[*]: bad array subscript
./assoc.tests: line 58: [*]=12: invalid associative array key
declare -A wheat='([six]="6" [foo bar]="qux qix" )'
argv[1] = <qux>
argv[2] = <qix>
argv[1] = <qux qix>
declare -A wheat='([six]="6" [foo bar]="qux qix" )'
argv[1] = <2>
argv[1] = <7>
argv[1] = <qux>
argv[2] = <qix>
argv[3] = <blat>
argv[1] = <qux qix blat>
argv[1] = <16>
argv[1] = <16>
argv[1] = <flix>
argv[2] = <6>
argv[1] = <six>
argv[2] = <foo>
argv[3] = <bar>
argv[1] = <six>
argv[2] = <foo bar>
8
/usr/local/bin . /bin /sbin /usr/sbin /usr/bin /bin /usr/ucb
bin . bin sbin sbin bin bin ucb
bin
/ / / / / / /
/
argv[1] = <bin>
argv[1] = </>
argv[1] = <sbin>
argv[1] = </>
8
/usr/local/bin . /bin /sbin /usr/sbin /usr/bin /bin /usr/ucb
bin . bin sbin sbin bin bin ucb
/ / / / / / /
8
4 -- /bin
^usr^local^bin . ^bin ^sbin ^usr^sbin ^usr^bin ^bin ^usr^ucb
^usr^local^bin . ^bin ^sbin ^usr^sbin ^usr^bin ^bin ^usr^ucb
\usr/local/bin . \bin \sbin \usr/sbin \usr/bin \bin \usr/ucb
\usr\local\bin . \bin \sbin \usr\sbin \usr\bin \bin \usr\ucb
\usr\local\bin . \bin \sbin \usr\sbin \usr\bin \bin \usr\ucb
qux foo
/usr/local/bin/qux /usr/sbin/foo
hits command
0 /sbin/blat
0 /usr/local/bin/qux
0 /bin/sh
0 /usr/sbin/foo
blat qux sh foo
/sbin/blat /usr/local/bin/qux /bin/sh /usr/sbin/foo
foo qux
argv[1] = </usr/sbin/foo>
argv[2] = </usr/local/bin/qux>
argv[3] = <-l>
alias blat='cd /blat ; echo $PWD'
alias foo='/usr/sbin/foo'
alias qux='/usr/local/bin/qux -l'
alias sh='/bin/bash --login -o posix'
sh foo blat qux
argv[1] = </bin/bash --login -o posix>
argv[2] = </usr/sbin/foo>
argv[3] = <cd /blat ; echo $PWD>
argv[4] = </usr/local/bin/qux -l>
+169
View File
@@ -0,0 +1,169 @@
# TEST - basic declaration and assignment
typeset -A fluff
declare -A
fluff[foo]=one
fluff[bar]=two
declare -A
declare -p fluff
unset fluff[foo]
declare -p fluff
fluff[bar]=newval
declare -p fluff
unset fluff
# TEST - compount assignment and variable attributes
declare -A wheat chaff
wheat=( [zero]=0 [one]=a [two]=b [three]=c )
declare -i chaff
chaff=( [zero]=1+4 [one]=3+7 four )
declare -A waste=( [pid]=42134 [version]=4.0-devel [source]=$0 [lineno]=$LINENO )
declare -r waste
declare -A
declare +i chaff
chaff[hello world]=flip
declare -p chaff
# TEST - errors
unset waste
chaff[*]=12
chaff=( [one]=a [*]=12 )
# TEST - key expansion -- no word splitting
chaff[hello world]=flip
declare -p chaff
echo ${chaff[hello world]}
chaff[box]="multiple words"
recho ${chaff[@]}
recho "${chaff[@]}"
recho ${chaff[*]}
recho "${chaff[*]}"
unset chaff
declare -A chaff[200]
declare +A chaff
chaff[*]=12
chaff=( [one]=a [*]=12 )
# TEST - keys and values containing spaces
unset wheat
declare -A wheat
wheat=([six]=6 [foo bar]="qux qix" )
declare -p wheat
unset wheat
declare -A wheat=([six]=6 [foo bar]="qux qix" )
recho ${wheat[foo bar]}
recho "${wheat[foo bar]}"
declare -p wheat
# TEST - basic expansions: number of elements and value length
unset wheat
typeset -A wheat
wheat=([six]=6 [foo bar]="qux qix" )
recho ${#wheat[@]}
recho ${#wheat[foo bar]}
# TEST - appending assignment operator
unset wheat
typeset -A wheat
wheat=([six]=6 [foo bar]="qux qix" )
wheat[foo bar]+=' blat'
recho ${wheat[foo bar]}
recho "${wheat[foo bar]}"
unset wheat
flix=9
typeset -Ai wheat
wheat=([six]=6 [foo bar]=flix )
wheat[foo bar]+=7
recho ${wheat[foo bar]}
recho "${wheat[foo bar]}"
unset flix wheat
# TEST - index expansion: no word splitting or globbing
typeset -A wheat
cd /tmp
touch '[sfiri]'
wheat=([s*]=6 [foo bar]=flix )
recho ${wheat[@]}
rm '[sfiri]'
cd $OLDPWD
# TEST -- associative array keys expansion
unset wheat
typeset -A wheat
wheat=([six]=6 [foo bar]=flix )
recho ${!wheat[@]}
recho "${!wheat[@]}"
# TEST -- associative array pattern removal
unset xpath
typeset -A xpath
xpath=( [0]=/bin [one]=/bin [two]=/usr/bin [three]=/usr/ucb [four]=/usr/local/bin)
xpath+=( [five]=/sbin [six]=/usr/sbin [seven]=. )
echo ${#xpath[@]}
echo ${xpath[@]}
echo ${xpath[@]##*/}
echo ${xpath[0]##*/}
echo ${xpath[@]%%[!/]*}
echo ${xpath[0]%%[!/]*}
recho ${xpath##*/}
recho ${xpath%%[!/]*}
recho ${xpath[five]##*/}
recho ${xpath[five]%%[!/]*}
echo ${#xpath[*]}
echo ${xpath[*]}
echo ${xpath[*]##*/}
echo ${xpath[*]%%[!/]*}
# TEST -- associative array pattern substitution
unset xpath
typeset -A xpath
xpath=( [0]=/bin [one]=/bin [two]=/usr/bin [three]=/usr/ucb [four]=/usr/local/bin)
xpath+=( [five]=/sbin [six]=/usr/sbin [seven]=. )
echo ${#xpath[@]}
# default element is "0" (as a string)
echo ${#xpath} -- ${xpath["0"]}
echo ${xpath[@]//\//^}
echo "${xpath[@]//\//^}" | cat -v
zecho "${xpath[@]/\//\\}"
zecho "${xpath[@]//\//\\}"
zecho "${xpath[@]//[\/]/\\}"
${THIS_SH} ./assoc1.sub
${THIS_SH} ./assoc2.sub
+16
View File
@@ -0,0 +1,16 @@
hash -r
echo ${BASH_CMDS[@]}
hash -p /usr/sbin/foo foo
hash -p /usr/local/bin/qux qux
echo ${!BASH_CMDS[@]}
echo ${BASH_CMDS[@]}
BASH_CMDS[blat]=/sbin/blat
BASH_CMDS[sh]=/bin/sh
hash
echo ${!BASH_CMDS[@]}
echo "${BASH_CMDS[@]}"
+15
View File
@@ -0,0 +1,15 @@
echo ${BASH_ALIASES[@]}
alias foo=/usr/sbin/foo
alias qux='/usr/local/bin/qux -l'
echo ${!BASH_ALIASES[@]}
recho ${BASH_ALIASES[@]}
BASH_ALIASES[blat]='cd /blat ; echo $PWD'
BASH_ALIASES[sh]='/bin/bash --login -o posix'
alias -p
echo ${!BASH_ALIASES[@]}
recho "${BASH_ALIASES[@]}"
+4
View File
@@ -0,0 +1,4 @@
echo "warning: all of these tests will fail if arrays have not" >&2
echo "warning: been compiled into the shell" >&2
${THIS_SH} ./assoc.tests > /tmp/xx 2>&1
diff /tmp/xx assoc.right && rm -f /tmp/xx
+6
View File
@@ -0,0 +1,6 @@
echo "warning: all of these tests will fail if arrays have not" >&2
echo "warning: been compiled into the shell" >&2
echo "warning: the BASH_ARGC and BASH_ARGV tests will fail if debugging support" >&2
echo "warning: has not been compiled into the shell" >&2
${THIS_SH} ./array.tests > /tmp/xx 2>&1
diff /tmp/xx array.right && rm -f /tmp/xx
+328 -80
View File
@@ -1,6 +1,6 @@
/* variables.c -- Functions for hacking shell variables. */
/* Copyright (C) 1987-2007 Free Software Foundation, Inc.
/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -50,6 +50,7 @@
#include "input.h"
#include "hashcmd.h"
#include "pathexp.h"
#include "alias.h"
#include "builtins/getopt.h"
#include "builtins/common.h"
@@ -169,30 +170,31 @@ static void uidset __P((void));
static void make_vers_array __P((void));
#endif
static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t));
static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
#if defined (ARRAY_VARS)
static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t));
static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
#endif
static SHELL_VAR *get_self __P((SHELL_VAR *));
#if defined (ARRAY_VARS)
static SHELL_VAR *init_dynamic_array_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
static SHELL_VAR *init_dynamic_assoc_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
#endif
static SHELL_VAR *assign_seconds __P((SHELL_VAR *, char *, arrayind_t));
static SHELL_VAR *assign_seconds __P((SHELL_VAR *, char *, arrayind_t, char *));
static SHELL_VAR *get_seconds __P((SHELL_VAR *));
static SHELL_VAR *init_seconds_var __P((void));
static int brand __P((void));
static void sbrand __P((unsigned long)); /* set bash random number generator. */
static void seedrand __P((void)); /* seed generator randomly */
static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t));
static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t, char *));
static SHELL_VAR *get_random __P((SHELL_VAR *));
static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t));
static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t, char *));
static SHELL_VAR *get_lineno __P((SHELL_VAR *));
static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t));
static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t, char *));
static SHELL_VAR *get_subshell __P((SHELL_VAR *));
static SHELL_VAR *get_bashpid __P((SHELL_VAR *));
@@ -201,13 +203,25 @@ static SHELL_VAR *get_bashpid __P((SHELL_VAR *));
static SHELL_VAR *get_histcmd __P((SHELL_VAR *));
#endif
#if defined (READLINE)
static SHELL_VAR *get_comp_wordbreaks __P((SHELL_VAR *));
static SHELL_VAR *assign_comp_wordbreaks __P((SHELL_VAR *, char *, arrayind_t, char *));
#endif
#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t));
static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t, char *));
static SHELL_VAR *get_dirstack __P((SHELL_VAR *));
#endif
#if defined (ARRAY_VARS)
static SHELL_VAR *get_groupset __P((SHELL_VAR *));
static SHELL_VAR *build_hashcmd __P((SHELL_VAR *));
static SHELL_VAR *get_hashcmd __P((SHELL_VAR *));
static SHELL_VAR *assign_hashcmd __P((SHELL_VAR *, char *, arrayind_t, char *));
static SHELL_VAR *build_aliasvar __P((SHELL_VAR *));
static SHELL_VAR *get_aliasvar __P((SHELL_VAR *));
static SHELL_VAR *assign_aliasvar __P((SHELL_VAR *, char *, arrayind_t, char *));
#endif
static SHELL_VAR *get_funcname __P((SHELL_VAR *));
@@ -220,6 +234,7 @@ static SHELL_VAR *new_shell_variable __P((const char *));
static SHELL_VAR *make_new_variable __P((const char *, HASH_TABLE *));
static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int, int));
static void dispose_variable_value __P((SHELL_VAR *));
static void free_variable_hash_data __P((PTR_T));
static VARLIST *vlist_alloc __P((int));
@@ -941,6 +956,8 @@ print_assignment (var)
#if defined (ARRAY_VARS)
else if (array_p (var))
print_array_assignment (var, 0);
else if (assoc_p (var))
print_assoc_assignment (var, 0);
#endif /* ARRAY_VARS */
else
{
@@ -1052,21 +1069,32 @@ print_var_function (var)
} \
while (0)
#define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \
do \
{ \
v = make_new_assoc_variable (var); \
v->dynamic_value = gfunc; \
v->assign_func = afunc; \
} \
while (0)
static SHELL_VAR *
null_assign (self, value, unused)
null_assign (self, value, unused, key)
SHELL_VAR *self;
char *value;
arrayind_t unused;
char *key;
{
return (self);
}
#if defined (ARRAY_VARS)
static SHELL_VAR *
null_array_assign (self, value, ind)
null_array_assign (self, value, ind, key)
SHELL_VAR *self;
char *value;
arrayind_t ind;
char *key;
{
return (self);
}
@@ -1101,8 +1129,25 @@ init_dynamic_array_var (name, getfunc, setfunc, attrs)
VSETATTR (v, attrs);
return v;
}
#endif
static SHELL_VAR *
init_dynamic_assoc_var (name, getfunc, setfunc, attrs)
char *name;
sh_var_value_func_t *getfunc;
sh_var_assign_func_t *setfunc;
int attrs;
{
SHELL_VAR *v;
v = find_variable (name);
if (v)
return (v);
INIT_DYNAMIC_ASSOC_VAR (name, getfunc, setfunc);
if (attrs)
VSETATTR (v, attrs);
return v;
}
#endif
/* The value of $SECONDS. This is the number of seconds since shell
invocation, or, the number of seconds since the last assignment + the
@@ -1110,10 +1155,11 @@ init_dynamic_array_var (name, getfunc, setfunc, attrs)
static intmax_t seconds_value_assigned;
static SHELL_VAR *
assign_seconds (self, value, unused)
assign_seconds (self, value, unused, key)
SHELL_VAR *self;
char *value;
arrayind_t unused;
char *key;
{
if (legal_number (value, &seconds_value_assigned) == 0)
seconds_value_assigned = 0;
@@ -1205,10 +1251,11 @@ seedrand ()
}
static SHELL_VAR *
assign_random (self, value, unused)
assign_random (self, value, unused, key)
SHELL_VAR *self;
char *value;
arrayind_t unused;
char *key;
{
sbrand (strtoul (value, (char **)NULL, 10));
if (subshell_environment)
@@ -1254,10 +1301,11 @@ get_random (var)
}
static SHELL_VAR *
assign_lineno (var, value, unused)
assign_lineno (var, value, unused, key)
SHELL_VAR *var;
char *value;
arrayind_t unused;
char *key;
{
intmax_t new_value;
@@ -1283,10 +1331,11 @@ get_lineno (var)
}
static SHELL_VAR *
assign_subshell (var, value, unused)
assign_subshell (var, value, unused, key)
SHELL_VAR *var;
char *value;
arrayind_t unused;
char *key;
{
intmax_t new_value;
@@ -1329,7 +1378,7 @@ get_bash_command (var)
SHELL_VAR *var;
{
char *p;
if (the_printed_command_except_trap)
p = savestring (the_printed_command_except_trap);
else
@@ -1366,7 +1415,6 @@ get_comp_wordbreaks (var)
if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0)
enable_hostname_completion (perform_hostname_completion);
itrace("get: rl_completer_word_break_characters = `%s'", rl_completer_word_break_characters);
var_setvalue (var, rl_completer_word_break_characters);
return (var);
@@ -1375,27 +1423,28 @@ itrace("get: rl_completer_word_break_characters = `%s'", rl_completer_word_break
/* When this function returns, rl_completer_word_break_characters points to
malloced memory. */
static SHELL_VAR *
assign_comp_wordbreaks (self, value, unused)
assign_comp_wordbreaks (self, value, unused, key)
SHELL_VAR *self;
char *value;
arrayind_t unused;
char *key;
{
if (rl_completer_word_break_characters &&
rl_completer_word_break_characters != rl_basic_word_break_characters)
free (rl_completer_word_break_characters);
rl_completer_word_break_characters = savestring (value);
itrace("assign: rl_completer_word_break_characters = `%s'", rl_completer_word_break_characters);
return self;
}
#endif /* READLINE */
#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
static SHELL_VAR *
assign_dirstack (self, value, ind)
assign_dirstack (self, value, ind, key)
SHELL_VAR *self;
char *value;
arrayind_t ind;
char *key;
{
set_dirstack_element (ind, 1, value);
return self;
@@ -1438,6 +1487,112 @@ get_groupset (self)
}
return (self);
}
static SHELL_VAR *
build_hashcmd (self)
SHELL_VAR *self;
{
HASH_TABLE *h;
int i;
char *k, *v;
BUCKET_CONTENTS *item;
h = assoc_cell (self);
if (h)
assoc_dispose (h);
if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0)
{
var_setvalue (self, (char *)NULL);
return self;
}
h = assoc_create (hashed_filenames->nbuckets);
for (i = 0; i < hashed_filenames->nbuckets; i++)
{
for (item = hash_items (i, hashed_filenames); item; item = item->next)
{
k = savestring (item->key);
v = pathdata(item)->path;
assoc_insert (h, k, v);
}
}
var_setvalue (self, (char *)h);
return self;
}
static SHELL_VAR *
get_hashcmd (self)
SHELL_VAR *self;
{
build_hashcmd (self);
return (self);
}
static SHELL_VAR *
assign_hashcmd (self, value, ind, key)
SHELL_VAR *self;
char *value;
arrayind_t ind;
char *key;
{
phash_insert (key, value, 0, 0);
return (build_hashcmd (self));
}
static SHELL_VAR *
build_aliasvar (self)
SHELL_VAR *self;
{
HASH_TABLE *h;
int i;
char *k, *v;
BUCKET_CONTENTS *item;
h = assoc_cell (self);
if (h)
assoc_dispose (h);
if (aliases == 0 || HASH_ENTRIES (aliases) == 0)
{
var_setvalue (self, (char *)NULL);
return self;
}
h = assoc_create (aliases->nbuckets);
for (i = 0; i < aliases->nbuckets; i++)
{
for (item = hash_items (i, aliases); item; item = item->next)
{
k = savestring (item->key);
v = ((alias_t *)(item->data))->value;
assoc_insert (h, k, v);
}
}
var_setvalue (self, (char *)h);
return self;
}
static SHELL_VAR *
get_aliasvar (self)
SHELL_VAR *self;
{
build_aliasvar (self);
return (self);
}
static SHELL_VAR *
assign_aliasvar (self, value, ind, key)
SHELL_VAR *self;
char *value;
arrayind_t ind;
char *key;
{
add_alias (key, value);
return (build_aliasvar (self));
}
#endif /* ARRAY_VARS */
/* If ARRAY_VARS is not defined, this just returns the name of any
@@ -1531,6 +1686,9 @@ initialize_dynamic_variables ()
# endif /* DEBUGGER */
v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset);
v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset);
v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_nofree);
v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree);
#endif
v = init_funcname_var ();
@@ -1577,7 +1735,7 @@ var_lookup (name, vcontext)
then also search the temporarily built list of exported variables.
The lookup order is:
temporary_env
shell_variables list
shell_variables list
*/
SHELL_VAR *
@@ -1650,6 +1808,8 @@ get_variable_value (var)
#if defined (ARRAY_VARS)
else if (array_p (var))
return (array_reference (array_cell (var), 0));
else if (assoc_p (var))
return (assoc_reference (assoc_cell (var), "0"));
#endif
else
return (value_cell (var));
@@ -1759,7 +1919,7 @@ make_local_variable (name)
inherit its value. Watch to see if this causes problems with
things like `x=4 local x'. */
if (was_tmpvar)
var_setvalue (new_var, savestring (tmp_value));
var_setvalue (new_var, savestring (tmp_value));
new_var->attributes = exported_p (old_var) ? att_exported : 0;
}
@@ -1775,27 +1935,6 @@ make_local_variable (name)
return (new_var);
}
#if defined (ARRAY_VARS)
SHELL_VAR *
make_local_array_variable (name)
char *name;
{
SHELL_VAR *var;
ARRAY *array;
var = make_local_variable (name);
if (var == 0 || array_p (var))
return var;
array = array_create ();
FREE (value_cell(var));
var_setarray (var, array);
VSETATTR (var, att_array);
return var;
}
#endif /* ARRAY_VARS */
/* Create a new shell variable with name NAME. */
static SHELL_VAR *
new_shell_variable (name)
@@ -1854,10 +1993,64 @@ make_new_array_variable (name)
entry = make_new_variable (name, global_variables->table);
array = array_create ();
var_setarray (entry, array);
VSETATTR (entry, att_array);
return entry;
}
SHELL_VAR *
make_local_array_variable (name)
char *name;
{
SHELL_VAR *var;
ARRAY *array;
var = make_local_variable (name);
if (var == 0 || array_p (var))
return var;
array = array_create ();
dispose_variable_value (var);
var_setarray (var, array);
VSETATTR (var, att_array);
return var;
}
SHELL_VAR *
make_new_assoc_variable (name)
char *name;
{
SHELL_VAR *entry;
HASH_TABLE *hash;
entry = make_new_variable (name, global_variables->table);
hash = assoc_create (0);
var_setassoc (entry, hash);
VSETATTR (entry, att_assoc);
return entry;
}
SHELL_VAR *
make_local_assoc_variable (name)
char *name;
{
SHELL_VAR *var;
HASH_TABLE *hash;
var = make_local_variable (name);
if (var == 0 || assoc_p (var))
return var;
dispose_variable_value (var);
hash = assoc_create (0);
var_setassoc (var, hash);
VSETATTR (var, att_assoc);
return var;
}
#endif
char *
@@ -1868,7 +2061,7 @@ make_variable_value (var, value, flags)
{
char *retval, *oval;
intmax_t lval, rval;
int expok, olen;
int expok, olen, op;
/* If this variable has had its type set to integer (via `declare -i'),
then do expression evaluation on it and store the result. The
@@ -1897,6 +2090,34 @@ make_variable_value (var, value, flags)
rval += lval;
retval = itos (rval);
}
#if defined (CASEMOD_ATTRS)
else if (capcase_p (var) || uppercase_p (var) || lowercase_p (var))
{
if (flags & ASS_APPEND)
{
oval = get_variable_value (var);
if (oval == 0) /* paranoia */
oval = "";
olen = STRLEN (oval);
retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
strcpy (retval, oval);
if (value)
strcpy (retval+olen, value);
}
#endif /* CASEMOD_ATTRS */
else if (*value)
retval = savestring (value);
else
{
retval = (char *)xmalloc (1);
retval[0] = '\0';
}
op = capcase_p (var) ? CASE_CAPITALIZE
: (uppercase_p (var) ? CASE_UPPER : CASE_LOWER);
oval = sh_modcase (retval, (char *)0, op);
free (retval);
retval = oval;
}
else if (value)
{
if (flags & ASS_APPEND)
@@ -1947,9 +2168,9 @@ bind_variable_internal (name, value, table, hflags, aflags)
{
INVALIDATE_EXPORTSTR (entry);
newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value;
entry = (*(entry->assign_func)) (entry, newval, -1);
entry = (*(entry->assign_func)) (entry, newval, -1, 0);
if (newval != value)
free (newval);
free (newval);
return (entry);
}
else
@@ -1979,6 +2200,11 @@ bind_variable_internal (name, value, table, hflags, aflags)
array_insert (array_cell (entry), 0, newval);
free (newval);
}
else if (assoc_p (entry))
{
assoc_insert (assoc_cell (entry), "0", newval);
free (newval);
}
else
#endif
{
@@ -2024,11 +2250,11 @@ bind_variable (name, value, flags)
for (vc = shell_variables; vc; vc = vc->down)
{
if (vc_isfuncenv (vc) || vc_isbltnenv (vc))
{
v = hash_lookup (name, vc->table);
if (v)
{
v = hash_lookup (name, vc->table);
if (v)
return (bind_variable_internal (name, value, vc->table, 0, flags));
}
}
}
return (bind_variable_internal (name, value, global_variables->table, 0, flags));
}
@@ -2053,7 +2279,7 @@ bind_variable_value (var, value, aflags)
/* If we're appending, we need the old value, so use
make_variable_value */
t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value;
(*(var->assign_func)) (var, t, -1);
(*(var->assign_func)) (var, t, -1, 0);
if (t != value && t)
free (t);
}
@@ -2311,7 +2537,9 @@ copy_variable (var)
var_setfunc (copy, copy_command (function_cell (var)));
#if defined (ARRAY_VARS)
else if (array_p (var))
var_setarray (copy, dup_array (array_cell (var)));
var_setarray (copy, array_copy (array_cell (var)));
else if (assoc_p (var))
var_setassoc (copy, assoc_copy (assoc_cell (var)));
#endif
else if (value_cell (var))
var_setvalue (copy, savestring (value_cell (var)));
@@ -2336,6 +2564,22 @@ copy_variable (var)
/* **************************************************************** */
/* Dispose of the information attached to VAR. */
static void
dispose_variable_value (var)
SHELL_VAR *var;
{
if (function_p (var))
dispose_command (function_cell (var));
#if defined (ARRAY_VARS)
else if (array_p (var))
array_dispose (array_cell (var));
else if (assoc_p (var))
assoc_dispose (assoc_cell (var));
#endif
else
FREE (value_cell (var));
}
void
dispose_variable (var)
SHELL_VAR *var;
@@ -2343,14 +2587,8 @@ dispose_variable (var)
if (var == 0)
return;
if (function_p (var))
dispose_command (function_cell (var));
#if defined (ARRAY_VARS)
else if (array_p (var))
array_dispose (array_cell (var));
#endif
else
FREE (value_cell (var));
if (nofree_p (var) == 0)
dispose_variable_value (var);
FREE_EXPORTSTR (var);
@@ -2459,15 +2697,19 @@ makunbound (name, vc)
We also need to add it back into the correct hash table. */
if (old_var && local_p (old_var) && variable_context == old_var->context)
{
if (nofree_p (old_var))
var_setvalue (old_var, (char *)NULL);
#if defined (ARRAY_VARS)
if (array_p (old_var))
else if (array_p (old_var))
array_dispose (array_cell (old_var));
else
else if (assoc_p (old_var))
assoc_dispose (assoc_cell (old_var));
#endif
else
FREE (value_cell (old_var));
/* Reset the attributes. Preserve the export attribute if the variable
came from a temporary environment. Make sure it stays local, and
make it invisible. */
came from a temporary environment. Make sure it stays local, and
make it invisible. */
old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0;
VSETATTR (old_var, att_local);
VSETATTR (old_var, att_invisible);
@@ -3030,7 +3272,7 @@ dispose_temporary_env (pushf)
{
hash_flush (temporary_env, pushf);
hash_dispose (temporary_env);
temporary_env = (HASH_TABLE *)NULL;
temporary_env = (HASH_TABLE *)NULL;
array_needs_making = 1;
@@ -3142,6 +3384,12 @@ make_env_array_from_var_list (vars)
value = array_to_assignment_string (array_cell (var));
# else
continue; /* XXX array vars cannot yet be exported */
# endif
else if (assoc_p (var))
# if 0
value = assoc_to_assignment_string (assoc_cell (var));
# else
continue; /* XXX associative array vars cannot yet be exported */
# endif
#endif
else
@@ -3162,7 +3410,7 @@ make_env_array_from_var_list (vars)
#if 0 /* not yet */
#if defined (ARRAY_VARS)
if (array_p (var))
if (array_p (var) || assoc_p (var))
free (value);
#endif
#endif
@@ -3316,7 +3564,7 @@ maybe_make_export_env ()
if (array_needs_making)
{
if (export_env)
strvec_flush (export_env);
strvec_flush (export_env);
/* Make a guess based on how many shell variables and functions we
have. Since there will always be array variables, and array
@@ -3333,24 +3581,24 @@ maybe_make_export_env ()
export_env[export_env_index = 0] = (char *)NULL;
/* Make a dummy variable context from the temporary_env, stick it on
the front of shell_variables, call make_var_export_array on the
whole thing to flatten it, and convert the list of SHELL_VAR *s
to the form needed by the environment. */
the front of shell_variables, call make_var_export_array on the
whole thing to flatten it, and convert the list of SHELL_VAR *s
to the form needed by the environment. */
if (temporary_env)
{
tcxt = new_var_context ((char *)NULL, 0);
tcxt->table = temporary_env;
tcxt->down = shell_variables;
}
{
tcxt = new_var_context ((char *)NULL, 0);
tcxt->table = temporary_env;
tcxt->down = shell_variables;
}
else
tcxt = shell_variables;
tcxt = shell_variables;
temp_array = make_var_export_array (tcxt);
if (temp_array)
add_temp_array_to_env (temp_array, 0, 0);
if (tcxt != shell_variables)
free (tcxt);
free (tcxt);
#if defined (RESTRICTED_SHELL)
/* Restricted shells may not export shell functions. */
@@ -3517,7 +3765,7 @@ push_func_var (data)
if (shell_variables == global_variables)
var->attributes &= ~(att_tempvar|att_propagate);
else
shell_variables->flags |= VC_HASTMPVAR;
shell_variables->flags |= VC_HASTMPVAR;
v->attributes |= var->attributes;
}
else
@@ -3564,7 +3812,7 @@ delete_all_contexts (vcxt)
{
t = v->down;
dispose_var_context (v);
}
}
delete_all_variables (global_variables->table);
shell_variables = global_variables;
@@ -3900,7 +4148,7 @@ find_special_var (name)
else if (r > 0)
/* Can't match any of rest of elements in sorted list. Take this out
if it causes problems in certain environments. */
break;
break;
}
return -1;
}