mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-27 07:43:07 +02:00
commit bash-20080626 snapshot
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+54
-16
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
@@ -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)
|
||||
|
||||
@@ -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--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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[@]}"
|
||||
@@ -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[@]}"
|
||||
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user