commit bash-20041104 snapshot

This commit is contained in:
Chet Ramey
2011-12-03 13:39:12 -05:00
parent 177d51f71e
commit d11b8b46f0
66 changed files with 4539 additions and 320 deletions
+1 -1
View File
@@ -184,7 +184,7 @@ n. Fixed the value of errno set by the pathname canonicalization functions.
o. Changed the grammar so that `time' alone on a line times a null command
rather than being a syntax error.
p. The pattern substitution coded no longer performs quote removal on the
p. The pattern substitution code no longer performs quote removal on the
pattern before trying to match it, as the pattern removal functions do.
q. Fixed a bug that could cause core dumps when checking whether a quoted
+11
View File
@@ -212,3 +212,14 @@ and bash-2.0 were significant.)
18. Bash no longer requires that the body of a function be a group command;
any compound command is accepted.
19. As of bash-3.0, the pattern substitution operators no longer perform
quote removal on the pattern before attempting the match. This is the
way the pattern removal functions behave, and is more consistent.
20. After bash-3.0 was released, I reimplemented tilde expansion, incorporating
it into the mainline word expansion code. This fixes the bug that caused
the results of tilde expansion to be re-expanded. There is one
incompatibility: a ${paramOPword} expansion within double quotes will not
perform tilde expansion on WORD. This is consistent with the other
expansions, and what POSIX specifies.
+76
View File
@@ -10475,3 +10475,79 @@ lib/readline/display.c
locale, it's used as an absolute cursor position; when not using
multibyte characters, it's a buffer offset. I should have caught
this when the multibyte character support was donated
11/5
----
general.c
- change `assignment()' to accept `+=' assignment operator
arrayfunc.[ch]
- bind_array_variable and assign_array_element both take a new `flags'
argument
- assign_array_var_from_string, assign_array_from_string, and
assign_array_var_from_word_list now all take a new `flags' argument
- change assign_array_var_from_word_list to understand how to append
to an array variable
- change assign_array_var_from_string to understand how to append
to an array variable. It does not unset the previous value if
appending, allowing both old values to be changed and new ones to
be added
subst.h
- new flag #defines to use for evaluating assignment statements
{subst,variables}.c, builtins/{declare,read}.def
- change callers of assign_array_element and bind_array_variable
- change do_compound_assignment to understand assignment flags
- change do_assignment_internal to set assignment flags and pass them
to underlying functions
pcomplete.c,builtins/{declare,read}.def
- fix callers of assign_array_var_from_string, assign_array_var_from_word_list
variables.[ch]
- make_variable_value now takes a new `flags' argument
- make_variable_value now understands how to append to a particular
variable, using the old value
- bind_variable_value now takes a new `flags' argument
- change make_variable_value to understand ASS_APPEND flag
- bind_variable now takes a new `flags' argument
- bind_variable_internal now takes a new `flags' argument
arrayfunc.c
- change callers of make_variable_value to add flags arg
builtins/declare.def
- change callers of bind_variable_value to add flags arg
{execute_cmd,mailcheck,pcomplete,shell,subst,variables}.c,parse.y
builtins/{cd,command,declare,getopts,read,set,setattr}.def
- change callers of bind_variable to add flags arg
variables.c
- change callers of bind_variable_internal
- change bind_variable_internal to pass assignment flags on to
make_variable_value
- change assign_in_env to treat `var+=value' like `var=value'
arrayfunc.c
- break code that actually constructs the new value and assigns it
to a particular array index out into a new functions:
bind_array_var_internal. This fakes out make_variable_value by
passing a dummy SHELL_VAR * so it can do proper appending and other
+= processing
- changes to assign_array_var_from_string to accept and process as if
they were `standalone' assignment statements array assignment words
of the form [ind]+=val
11/7
----
builtins/declare.def
- added support for `declare [flags] var+=value'. `Flags' are applied
before the assignment is performed, which has implications for things
like `-i' -- if -i is supplied, arithmetic evaluation and increment
will be performed
builtins/setattr.def
- add support for `+=' assignment for rest of `assignment builtins':
export, readonly
+84
View File
@@ -10463,3 +10463,87 @@ shell.c
lib/readline/display.c
- disable `fast redisplay' at the end of the line if in a locale that
supports multibyte characters (from SUSE, but not sent in)
lib/readline/histexpand.c
- fix a problem with finding the delimiter of a `?' substring when
compiled for multibyte characters (from SUSE, but not sent in)
11/1
----
lib/readline/display.c
- correct some assignments to _rl_last_c_pos: when in a multibyte
locale, it's used as an absolute cursor position; when not using
multibyte characters, it's a buffer offset. I should have caught
this when the multibyte character support was donated
11/5
----
general.c
- change `assignment()' to accept `+=' assignment operator
arrayfunc.[ch]
- bind_array_variable and assign_array_element both take a new `flags'
argument
- assign_array_var_from_string, assign_array_from_string, and
assign_array_var_from_word_list now all take a new `flags' argument
- change assign_array_var_from_word_list to understand how to append
to an array variable
- change assign_array_var_from_string to understand how to append
to an array variable. It does not unset the previous value if
appending, allowing both old values to be changed and new ones to
be added
subst.h
- new flag #defines to use for evaluating assignment statements
{subst,variables}.c, builtins/{declare,read}.def
- change callers of assign_array_element and bind_array_variable
- change do_compound_assignment to understand assignment flags
- change do_assignment_internal to set assignment flags and pass them
to underlying functions
pcomplete.c,builtins/{declare,read}.def
- fix callers of assign_array_var_from_string, assign_array_var_from_word_list
variables.[ch]
- make_variable_value now takes a new `flags' argument
- make_variable_value now understands how to append to a particular
variable, using the old value
- bind_variable_value now takes a new `flags' argument
- change make_variable_value to understand ASS_APPEND flag
- bind_variable now takes a new `flags' argument
- bind_variable_internal now takes a new `flags' argument
arrayfunc.c
- change callers of make_variable_value to add flags arg
builtins/declare.def
- change callers of bind_variable_value to add flags arg
{execute_cmd,mailcheck,pcomplete,shell,subst,variables}.c,parse.y
builtins/{cd,command,declare,getopts,read,set,setattr}.def
- change callers of bind_variable to add flags arg
variables.c
- change callers of bind_variable_internal
- change bind_variable_internal to pass assignment flags on to
make_variable_value
- change assign_in_env to treat `var+=value' like `var=value'
arrayfunc.c
- break code that actually constructs the new value and assigns it
to a particular array index out into a new functions:
bind_array_var_internal. This fakes out make_variable_value by
passing a dummy SHELL_VAR * so it can do proper appending and other
+= processing
- changes to assign_array_var_from_string to accept and process as if
they were `standalone' assignment statements array assignment words
of the form [ind]+=val
11/7
----
builtins/declare.def
- added support for `declare [flags] var+=value'. `Flags' are applied
before the assignment is performed, which has implications for things
like `-i' -- if -i is supplied, arithmetic evaluation and increment
will be performed
+1
View File
@@ -685,6 +685,7 @@ tests/array.tests f
tests/array.right f
tests/array1.sub f
tests/array2.sub f
tests/array3.sub f
tests/array-at-star f
tests/array2.right f
tests/braces.tests f
+2 -3
View File
@@ -243,9 +243,7 @@ char *s;
{
register ARRAY_ELEMENT *ae, *new;
if (a == 0)
return 0;
else if (array_empty(a) && s == 0)
if (a == 0 || (array_empty(a) && s == 0))
return 0;
else if (n <= 0)
return (a->num_elements);
@@ -558,6 +556,7 @@ ARRAY *a;
return (REVERSE_LIST(list, WORD_LIST *));
}
/* XXX - changes needed to support `+=' */
ARRAY *
array_assign_list (array, list)
ARRAY *array;
+81 -28
View File
@@ -1,6 +1,6 @@
/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
/* Copyright (C) 2001-2003 Free Software Foundation, Inc.
/* Copyright (C) 2001-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -39,6 +39,8 @@ 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 void quote_array_assignment_chars __P((WORD_LIST *));
static char *array_value_internal __P((char *, int, int, int *));
@@ -82,6 +84,49 @@ convert_var_to_array (var)
return var;
}
static SHELL_VAR *
bind_array_var_internal (entry, ind, value, flags)
SHELL_VAR *entry;
arrayind_t ind;
char *value;
int flags;
{
SHELL_VAR *dentry;
char *newval;
/* If we're appending, we need the old value of the array reference, so
fake out make_variable_value with a dummy SHELL_VAR */
if (flags & ASS_APPEND)
{
dentry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
dentry->name = savestring (entry->name);
newval = array_reference (array_cell (entry), ind);
if (newval)
dentry->value = savestring (newval);
else
{
dentry->value = (char *)xmalloc (1);
dentry->value[0] = '\0';
}
dentry->exportstr = 0;
dentry->attributes = entry->attributes & ~(att_array|att_exported);
/* Leave the rest of the members uninitialized; the code doesn't look
at them. */
newval = make_variable_value (dentry, value, flags);
dispose_variable (dentry);
}
else
newval = make_variable_value (entry, value, flags);
if (entry->assign_func)
(*entry->assign_func) (entry, newval, ind);
else
array_insert (array_cell (entry), ind, newval);
FREE (newval);
return (entry);
}
/* Perform an array assignment name[ind]=value. If NAME already exists and
is not an array, and IND is 0, perform name=value instead. If NAME exists
and is not an array, and IND is not 0, convert it into an array with the
@@ -90,13 +135,13 @@ convert_var_to_array (var)
If NAME does not exist, just create an array variable, no matter what
IND's value may be. */
SHELL_VAR *
bind_array_variable (name, ind, value)
bind_array_variable (name, ind, value, flags)
char *name;
arrayind_t ind;
char *value;
int flags;
{
SHELL_VAR *entry;
char *newval;
entry = var_lookup (name, shell_variables);
@@ -112,21 +157,15 @@ bind_array_variable (name, ind, value)
entry = convert_var_to_array (entry);
/* ENTRY is an array variable, and ARRAY points to the value. */
newval = make_variable_value (entry, value);
if (entry->assign_func)
(*entry->assign_func) (entry, newval, ind);
else
array_insert (array_cell (entry), ind, newval);
FREE (newval);
return (entry);
return (bind_array_var_internal (entry, ind, 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 *
assign_array_element (name, value)
assign_array_element (name, value, flags)
char *name, *value;
int flags;
{
char *sub, *vname;
arrayind_t ind;
@@ -153,7 +192,7 @@ assign_array_element (name, value)
return ((SHELL_VAR *)NULL);
}
entry = bind_array_variable (vname, ind, value);
entry = bind_array_variable (vname, ind, value, flags);
free (vname);
return (entry);
@@ -190,8 +229,9 @@ find_or_make_array_variable (name, check_flags)
/* Perform a compound assignment statement for array NAME, where VALUE is
the text between the parens: NAME=( VALUE ) */
SHELL_VAR *
assign_array_from_string (name, value)
assign_array_from_string (name, value, flags)
char *name, *value;
int flags;
{
SHELL_VAR *var;
@@ -199,21 +239,25 @@ assign_array_from_string (name, value)
if (var == 0)
return ((SHELL_VAR *)NULL);
return (assign_array_var_from_string (var, value));
return (assign_array_var_from_string (var, value, flags));
}
/* Sequentially assign the indices of indexed array variable VAR from the
words in LIST. */
SHELL_VAR *
assign_array_var_from_word_list (var, list)
assign_array_var_from_word_list (var, list, flags)
SHELL_VAR *var;
WORD_LIST *list;
int flags;
{
register arrayind_t i;
register WORD_LIST *l;
ARRAY *a;
for (a = array_cell (var), l = list, i = 0; l; l = l->next, i++)
a = array_cell (var);
i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
for (l = list; l; l = l->next, i++)
if (var->assign_func)
(*var->assign_func) (var, l->word->word, i);
else
@@ -224,9 +268,10 @@ assign_array_var_from_word_list (var, list)
/* Perform a compound array assignment: VAR->name=( VALUE ). The
VALUE has already had the parentheses stripped. */
SHELL_VAR *
assign_array_var_from_string (var, value)
assign_array_var_from_string (var, value, flags)
SHELL_VAR *var;
char *value;
int flags;
{
ARRAY *a;
WORD_LIST *list, *nlist;
@@ -274,10 +319,11 @@ assign_array_var_from_string (var, value)
/* Now that we are ready to assign values to the array, kill the existing
value. */
if (a)
if (a && (flags & ASS_APPEND) == 0)
array_flush (a);
last_ind = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
for (last_ind = 0, list = nlist; list; list = list->next)
for (list = nlist; list; list = list->next)
{
w = list->word->word;
@@ -286,9 +332,14 @@ assign_array_var_from_string (var, value)
{
len = skipsubscript (w, 0);
#if 1
/* XXX - changes for `+=' */
if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
#else
if (w[len] != ']' || w[len+1] != '=')
#endif
{
nval = make_variable_value (var, w);
nval = make_variable_value (var, w, flags);
if (var->assign_func)
(*var->assign_func) (var, nval, last_ind);
else
@@ -317,7 +368,14 @@ assign_array_var_from_string (var, value)
continue;
}
last_ind = ind;
val = w + len + 2;
/* XXX - changes for `+=' */
if (w[len + 1] == '+' && w[len + 2] == '=')
{
flags |= ASS_APPEND;
val = w + len + 3;
}
else
val = w + len + 2;
}
else /* No [ind]=value, just a stray `=' */
{
@@ -327,12 +385,7 @@ assign_array_var_from_string (var, value)
if (integer_p (var))
this_command_name = (char *)NULL; /* no command name for errors */
nval = make_variable_value (var, val);
if (var->assign_func)
(*var->assign_func) (var, nval, ind);
else
array_insert (a, ind, nval);
FREE (nval);
bind_array_var_internal (var, ind, val, flags);
last_ind++;
}
+803
View File
@@ -0,0 +1,803 @@
/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
/* Copyright (C) 2001-2004 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. */
#include "config.h"
#if defined (ARRAY_VARS)
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include "bashintl.h"
#include "shell.h"
#include "shmbutil.h"
#include "builtins/common.h"
extern char *this_command_name;
extern int last_command_exit_value;
extern int array_needs_making;
static void quote_array_assignment_chars __P((WORD_LIST *));
static char *array_value_internal __P((char *, int, int, int *));
/* Standard error message to use when encountering an invalid array subscript */
char *bash_badsub_errmsg = N_("bad array subscript");
/* **************************************************************** */
/* */
/* Functions to manipulate array variables and perform assignments */
/* */
/* **************************************************************** */
/* Convert a shell variable to an array variable. The original value is
saved as array[0]. */
SHELL_VAR *
convert_var_to_array (var)
SHELL_VAR *var;
{
char *oldval;
ARRAY *array;
oldval = value_cell (var);
array = array_create ();
if (oldval)
array_insert (array, 0, oldval);
FREE (value_cell (var));
var_setarray (var, array);
/* 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_array);
VUNSETATTR (var, att_invisible);
return var;
}
/* Perform an array assignment name[ind]=value. If NAME already exists and
is not an array, and IND is 0, perform name=value instead. If NAME exists
and is not an array, and IND is not 0, convert it into an array with the
existing value as name[0].
If NAME does not exist, just create an array variable, no matter what
IND's value may be. */
SHELL_VAR *
bind_array_variable (name, ind, value, flags)
char *name;
arrayind_t ind;
char *value;
int flags;
{
SHELL_VAR *entry, *dentry;
char *newval;
entry = var_lookup (name, shell_variables);
if (entry == (SHELL_VAR *) 0)
entry = make_new_array_variable (name);
else if (readonly_p (entry) || noassign_p (entry))
{
if (readonly_p (entry))
err_readonly (name);
return (entry);
}
else if (array_p (entry) == 0)
entry = convert_var_to_array (entry);
/* ENTRY is an array variable, and ARRAY points to the value. */
/* If we're appending, we need the old value of the array reference, so
fake out make_variable_value with a dummy SHELL_VAR */
if (flags & ASS_APPEND)
{
dentry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
dentry->name = savestring (entry->name);
newval = array_reference (array_cell (entry), ind);
if (newval)
dentry->value = savestring (newval);
else
{
dentry->value = (char *)xmalloc (1);
dentry->value[0] = '\0';
}
dentry->exportstr = 0;
dentry->attributes = entry->attributes & ~(att_array|att_exported);
/* Leave the rest of the members uninitialized; the code doesn't look
at them. */
newval = make_variable_value (dentry, value, flags);
dispose_variable (dentry);
}
else
newval = make_variable_value (entry, value, flags);
if (entry->assign_func)
(*entry->assign_func) (entry, newval, ind);
else
array_insert (array_cell (entry), ind, newval);
FREE (newval);
return (entry);
}
/* 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 *
assign_array_element (name, value, flags)
char *name, *value;
int flags;
{
char *sub, *vname;
arrayind_t ind;
int sublen;
SHELL_VAR *entry;
vname = array_variable_name (name, &sub, &sublen);
if (vname == 0)
return ((SHELL_VAR *)NULL);
if ((ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']') || (sublen <= 1))
{
free (vname);
err_badarraysub (name);
return ((SHELL_VAR *)NULL);
}
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);
}
/* 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
variable is checked for the readonly or noassign attribute in preparation
for assignment (e.g., by the `read' builtin). */
SHELL_VAR *
find_or_make_array_variable (name, check_flags)
char *name;
int check_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)))
{
if (readonly_p (var))
err_readonly (name);
return ((SHELL_VAR *)NULL);
}
else if (array_p (var) == 0)
var = convert_var_to_array (var);
return (var);
}
/* Perform a compound assignment statement for array NAME, where VALUE is
the text between the parens: NAME=( VALUE ) */
SHELL_VAR *
assign_array_from_string (name, value, flags)
char *name, *value;
int flags;
{
SHELL_VAR *var;
var = find_or_make_array_variable (name, 1);
if (var == 0)
return ((SHELL_VAR *)NULL);
return (assign_array_var_from_string (var, value, flags));
}
/* Sequentially assign the indices of indexed array variable VAR from the
words in LIST. */
SHELL_VAR *
assign_array_var_from_word_list (var, list, flags)
SHELL_VAR *var;
WORD_LIST *list;
int flags;
{
register arrayind_t i;
register WORD_LIST *l;
ARRAY *a;
a = array_cell (var);
i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
for (l = list; l; l = l->next, i++)
if (var->assign_func)
(*var->assign_func) (var, l->word->word, i);
else
array_insert (a, i, l->word->word);
return var;
}
/* Perform a compound array assignment: VAR->name=( VALUE ). The
VALUE has already had the parentheses stripped. */
SHELL_VAR *
assign_array_var_from_string (var, value, flags)
SHELL_VAR *var;
char *value;
int flags;
{
ARRAY *a;
WORD_LIST *list, *nlist;
char *w, *val, *nval;
int ni, len;
arrayind_t ind, last_ind;
if (value == 0)
return var;
/* If this is called from declare_builtin, value[0] == '(' and
xstrchr(value, ')') != 0. In this case, we need to extract
the value from between the parens before going on. */
if (*value == '(') /*)*/
{
ni = 1;
val = extract_array_assignment_list (value, &ni);
if (val == 0)
return var;
}
else
val = value;
/* Expand the value string into a list of words, performing all the
shell expansions including pathname generation and word splitting. */
/* First we split the string on whitespace, using the shell parser
(ksh93 seems to do this). */
list = parse_string_to_word_list (val, 1, "array assign");
/* If we're using [subscript]=value, we need to quote each [ and ] to
prevent unwanted filename expansion. */
if (list)
quote_array_assignment_chars (list);
/* Now that we've split it, perform the shell expansions on each
word in the list. */
nlist = list ? expand_words_no_vars (list) : (WORD_LIST *)NULL;
dispose_words (list);
if (val != value)
free (val);
a = array_cell (var);
/* 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;
for (list = nlist; list; list = list->next)
{
w = list->word->word;
/* We have a word of the form [ind]=value */
if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
{
len = skipsubscript (w, 0);
#if 1
if (! (w[len] == ']' && (w[len+1] == '=' || (w[len+1] == '+' && w[len+2] == '='))))
#else
if (w[len] != ']' || w[len+1] != '=')
#endif
{
nval = make_variable_value (var, w, flags);
if (var->assign_func)
(*var->assign_func) (var, nval, last_ind);
else
array_insert (a, last_ind, nval);
FREE (nval);
last_ind++;
continue;
}
if (len == 1)
{
err_badarraysub (w);
continue;
}
if (ALL_ELEMENT_SUB (w[1]) && len == 2)
{
report_error (_("%s: cannot assign to non-numeric index"), w);
continue;
}
ind = array_expand_index (w + 1, len);
if (ind < 0)
{
err_badarraysub (w);
continue;
}
last_ind = ind;
val = w + len + 2;
}
else /* No [ind]=value, just a stray `=' */
{
ind = last_ind;
val = w;
}
if (integer_p (var))
this_command_name = (char *)NULL; /* no command name for errors */
nval = make_variable_value (var, val, flags);
if (var->assign_func)
(*var->assign_func) (var, nval, ind);
else
array_insert (a, ind, nval);
FREE (nval);
last_ind++;
}
dispose_words (nlist);
return (var);
}
/* 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. */
static void
quote_array_assignment_chars (list)
WORD_LIST *list;
{
char *s, *t, *nword;
int saw_eq;
WORD_LIST *l;
for (l = list; l; l = l->next)
{
if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
continue; /* should not happen, but just in case... */
/* 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';
free (l->word->word);
l->word->word = nword;
}
}
/* This function assumes s[i] == '['; returns with s[ret] == ']' if
an array subscript is correctly parsed. */
int
skipsubscript (s, i)
const char *s;
int i;
{
int count, c;
#if defined (HANDLE_MULTIBYTE)
mbstate_t state, state_bak;
size_t slength, mblength;
size_t mb_cur_max;
#endif
#if defined (HANDLE_MULTIBYTE)
memset (&state, '\0', sizeof (mbstate_t));
slength = strlen (s + i);
mb_cur_max = MB_CUR_MAX;
#endif
count = 1;
while (count)
{
/* Advance one (possibly multibyte) character in S starting at I. */
#if defined (HANDLE_MULTIBYTE)
if (mb_cur_max > 1)
{
state_bak = state;
mblength = mbrlen (s + i, slength, &state);
if (MB_INVALIDCH (mblength))
{
state = state_bak;
i++;
slength--;
}
else if (MB_NULLWCH (mblength))
return i;
else
{
i += mblength;
slength -= mblength;
}
}
else
#endif
++i;
c = s[i];
if (c == 0)
break;
else if (c == '[')
count++;
else if (c == ']')
count--;
}
return i;
}
/* This function is called with SUB pointing to just after the beginning
`[' of an array subscript and removes the array element to which SUB
expands from array VAR. A subscript of `*' or `@' unsets the array. */
int
unbind_array_element (var, sub)
SHELL_VAR *var;
char *sub;
{
int len;
arrayind_t ind;
ARRAY_ELEMENT *ae;
len = skipsubscript (sub, 0);
if (sub[len] != ']' || len == 0)
{
builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg));
return -1;
}
sub[len] = '\0';
if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0)
{
unbind_variable (var->name);
return (0);
}
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;
}
/* Format and output an array assignment in compound form VAR=(VALUES),
suitable for re-use as input. */
void
print_array_assignment (var, quoted)
SHELL_VAR *var;
int quoted;
{
char *vstr;
vstr = array_to_assign (array_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 */
/* */
/***********************************************************************/
/* Return 1 if NAME is a properly-formed array reference v[sub]. */
int
valid_array_reference (name)
char *name;
{
char *t;
int r, len;
t = xstrchr (name, '['); /* ] */
if (t)
{
*t = '\0';
r = legal_identifier (name);
*t = '[';
if (r == 0)
return 0;
/* Check for a properly-terminated non-blank subscript. */
len = skipsubscript (t, 0);
if (t[len] != ']' || len == 1)
return 0;
for (r = 1; r < len; r++)
if (whitespace (t[r]) == 0)
return 1;
return 0;
}
return 0;
}
/* Expand the array index beginning at S and extending LEN characters. */
arrayind_t
array_expand_index (s, len)
char *s;
int len;
{
char *exp, *t;
int expok;
arrayind_t val;
exp = (char *)xmalloc (len);
strncpy (exp, s, len - 1);
exp[len - 1] = '\0';
t = expand_string_to_string (exp, 0);
this_command_name = (char *)NULL;
val = evalexp (t, &expok);
free (t);
free (exp);
if (expok == 0)
{
last_command_exit_value = EXECUTION_FAILURE;
jump_to_top_level (DISCARD);
}
return val;
}
/* Return the name of the variable specified by S without any subscript.
If SUBP is non-null, return a pointer to the start of the subscript
in *SUBP. If LENP is non-null, the length of the subscript is returned
in *LENP. This returns newly-allocated memory. */
char *
array_variable_name (s, subp, lenp)
char *s, **subp;
int *lenp;
{
char *t, *ret;
int ind, ni;
t = xstrchr (s, '[');
if (t == 0)
{
if (subp)
*subp = t;
if (lenp)
*lenp = 0;
return ((char *)NULL);
}
ind = t - s;
ni = skipsubscript (s, ind);
if (ni <= ind + 1 || s[ni] != ']')
{
err_badarraysub (s);
if (subp)
*subp = t;
if (lenp)
*lenp = 0;
return ((char *)NULL);
}
*t = '\0';
ret = savestring (s);
*t++ = '['; /* ] */
if (subp)
*subp = t;
if (lenp)
*lenp = ni - ind;
return ret;
}
/* Return the variable specified by S without any subscript. If SUBP is
non-null, return a pointer to the start of the subscript in *SUBP.
If LENP is non-null, the length of the subscript is returned in *LENP. */
SHELL_VAR *
array_variable_part (s, subp, lenp)
char *s, **subp;
int *lenp;
{
char *t;
SHELL_VAR *var;
t = array_variable_name (s, subp, lenp);
if (t == 0)
return ((SHELL_VAR *)NULL);
var = find_variable (t);
free (t);
return (var == 0 || invisible_p (var)) ? (SHELL_VAR *)0 : var;
}
/* Return a string containing the elements in the array and subscript
described by S. If the subscript is * or @, obeys quoting rules akin
to the expansion of $* and $@ including double quoting. If RTYPE
is non-null it gets 1 if the array reference is name[@] or name[*]
and 0 otherwise. */
static char *
array_value_internal (s, quoted, allow_all, rtype)
char *s;
int quoted, allow_all, *rtype;
{
int len;
arrayind_t ind;
char *retval, *t, *temp;
WORD_LIST *l;
SHELL_VAR *var;
var = array_variable_part (s, &t, &len);
/* Expand the index, even if the variable doesn't exist, in case side
effects are needed, like ${w[i++]} where w is unset. */
#if 0
if (var == 0)
return (char *)NULL;
#endif
if (len == 0)
return ((char *)NULL); /* error message already printed */
/* [ */
if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
{
if (rtype)
*rtype = 1;
if (allow_all == 0)
{
err_badarraysub (s);
return ((char *)NULL);
}
else if (var == 0)
return ((char *)NULL);
else if (array_p (var) == 0)
l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
else
{
l = array_to_word_list (array_cell (var));
if (l == (WORD_LIST *)NULL)
return ((char *) NULL);
}
if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
{
temp = string_list_dollar_star (l);
retval = quote_string (temp);
free (temp);
}
else /* ${name[@]} or unquoted ${name[*]} */
retval = string_list_dollar_at (l, quoted);
dispose_words (l);
}
else
{
if (rtype)
*rtype = 0;
ind = array_expand_index (t, len);
if (ind < 0)
{
if (var)
err_badarraysub (var->name);
else
{
t[-1] = '\0';
err_badarraysub (s);
t[-1] = '['; /* ] */
}
return ((char *)NULL);
}
if (var == 0)
return ((char *)NULL);
if (array_p (var) == 0)
return (ind == 0 ? value_cell (var) : (char *)NULL);
retval = array_reference (array_cell (var), ind);
}
return retval;
}
/* Return a string containing the elements described by the array and
subscript contained in S, obeying quoting for subscripts * and @. */
char *
array_value (s, quoted, rtype)
char *s;
int quoted, *rtype;
{
return (array_value_internal (s, quoted, 1, rtype));
}
/* Return the value of the array indexing expression S as a single string.
If ALLOW_ALL is 0, do not allow `@' and `*' subscripts. This is used
by other parts of the shell such as the arithmetic expression evaluator
in expr.c. */
char *
get_array_value (s, allow_all, rtype)
char *s;
int allow_all, *rtype;
{
return (array_value_internal (s, 0, allow_all, rtype));
}
char *
array_keys (s, quoted)
char *s;
int quoted;
{
int len;
char *retval, *t, *temp;
WORD_LIST *l;
SHELL_VAR *var;
var = array_variable_part (s, &t, &len);
/* [ */
if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']')
return (char *)NULL;
if (array_p (var) == 0)
l = add_string_to_list ("0", (WORD_LIST *)NULL);
else
{
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)))
{
temp = string_list_dollar_star (l);
retval = quote_string (temp);
free (temp);
}
else /* ${!name[@]} or unquoted ${!name[*]} */
retval = string_list_dollar_at (l, quoted);
dispose_words (l);
return retval;
}
#endif /* ARRAY_VARS */
+88 -27
View File
@@ -1,6 +1,6 @@
/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
/* Copyright (C) 2001-2003 Free Software Foundation, Inc.
/* Copyright (C) 2001-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -37,6 +37,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 void quote_array_assignment_chars __P((WORD_LIST *));
static char *array_value_internal __P((char *, int, int, int *));
@@ -72,6 +75,8 @@ convert_var_to_array (var)
var->assign_func = (sh_var_assign_func_t *)NULL;
INVALIDATE_EXPORTSTR (var);
if (exported_p (var))
array_needs_making++;
VSETATTR (var, att_array);
VUNSETATTR (var, att_invisible);
@@ -79,6 +84,49 @@ convert_var_to_array (var)
return var;
}
static SHELL_VAR *
bind_array_var_internal (entry, ind, value, flags)
SHELL_VAR *entry;
arrayind_t ind;
char *value;
int flags;
{
SHELL_VAR *dentry;
char *newval;
/* If we're appending, we need the old value of the array reference, so
fake out make_variable_value with a dummy SHELL_VAR */
if (flags & ASS_APPEND)
{
dentry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
dentry->name = savestring (entry->name);
newval = array_reference (array_cell (entry), ind);
if (newval)
dentry->value = savestring (newval);
else
{
dentry->value = (char *)xmalloc (1);
dentry->value[0] = '\0';
}
dentry->exportstr = 0;
dentry->attributes = entry->attributes & ~(att_array|att_exported);
/* Leave the rest of the members uninitialized; the code doesn't look
at them. */
newval = make_variable_value (dentry, value, flags);
dispose_variable (dentry);
}
else
newval = make_variable_value (entry, value, flags);
if (entry->assign_func)
(*entry->assign_func) (entry, newval, ind);
else
array_insert (array_cell (entry), ind, newval);
FREE (newval);
return (entry);
}
/* Perform an array assignment name[ind]=value. If NAME already exists and
is not an array, and IND is 0, perform name=value instead. If NAME exists
and is not an array, and IND is not 0, convert it into an array with the
@@ -87,13 +135,13 @@ convert_var_to_array (var)
If NAME does not exist, just create an array variable, no matter what
IND's value may be. */
SHELL_VAR *
bind_array_variable (name, ind, value)
bind_array_variable (name, ind, value, flags)
char *name;
arrayind_t ind;
char *value;
int flags;
{
SHELL_VAR *entry;
char *newval;
entry = var_lookup (name, shell_variables);
@@ -109,21 +157,15 @@ bind_array_variable (name, ind, value)
entry = convert_var_to_array (entry);
/* ENTRY is an array variable, and ARRAY points to the value. */
newval = make_variable_value (entry, value);
if (entry->assign_func)
(*entry->assign_func) (entry, newval, ind);
else
array_insert (array_cell (entry), ind, newval);
FREE (newval);
return (entry);
return (bind_array_var_internal (entry, ind, 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 *
assign_array_element (name, value)
assign_array_element (name, value, flags)
char *name, *value;
int flags;
{
char *sub, *vname;
arrayind_t ind;
@@ -150,7 +192,7 @@ assign_array_element (name, value)
return ((SHELL_VAR *)NULL);
}
entry = bind_array_variable (vname, ind, value);
entry = bind_array_variable (vname, ind, value, flags);
free (vname);
return (entry);
@@ -187,8 +229,9 @@ find_or_make_array_variable (name, check_flags)
/* Perform a compound assignment statement for array NAME, where VALUE is
the text between the parens: NAME=( VALUE ) */
SHELL_VAR *
assign_array_from_string (name, value)
assign_array_from_string (name, value, flags)
char *name, *value;
int flags;
{
SHELL_VAR *var;
@@ -196,21 +239,25 @@ assign_array_from_string (name, value)
if (var == 0)
return ((SHELL_VAR *)NULL);
return (assign_array_var_from_string (var, value));
return (assign_array_var_from_string (var, value, flags));
}
/* Sequentially assign the indices of indexed array variable VAR from the
words in LIST. */
SHELL_VAR *
assign_array_var_from_word_list (var, list)
assign_array_var_from_word_list (var, list, flags)
SHELL_VAR *var;
WORD_LIST *list;
int flags;
{
register arrayind_t i;
register WORD_LIST *l;
ARRAY *a;
for (a = array_cell (var), l = list, i = 0; l; l = l->next, i++)
a = array_cell (var);
i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
for (l = list; l; l = l->next, i++)
if (var->assign_func)
(*var->assign_func) (var, l->word->word, i);
else
@@ -221,9 +268,10 @@ assign_array_var_from_word_list (var, list)
/* Perform a compound array assignment: VAR->name=( VALUE ). The
VALUE has already had the parentheses stripped. */
SHELL_VAR *
assign_array_var_from_string (var, value)
assign_array_var_from_string (var, value, flags)
SHELL_VAR *var;
char *value;
int flags;
{
ARRAY *a;
WORD_LIST *list, *nlist;
@@ -271,10 +319,11 @@ assign_array_var_from_string (var, value)
/* Now that we are ready to assign values to the array, kill the existing
value. */
if (a)
if (a && (flags & ASS_APPEND) == 0)
array_flush (a);
last_ind = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
for (last_ind = 0, list = nlist; list; list = list->next)
for (list = nlist; list; list = list->next)
{
w = list->word->word;
@@ -283,9 +332,14 @@ assign_array_var_from_string (var, value)
{
len = skipsubscript (w, 0);
#if 1
/* XXX - changes for `+=' */
if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
#else
if (w[len] != ']' || w[len+1] != '=')
#endif
{
nval = make_variable_value (var, w);
nval = make_variable_value (var, w, flags);
if (var->assign_func)
(*var->assign_func) (var, nval, last_ind);
else
@@ -314,7 +368,14 @@ assign_array_var_from_string (var, value)
continue;
}
last_ind = ind;
val = w + len + 2;
/* XXX - changes for `+=' */
if (w[len + 1] == '+' && w[len + 2] == '=')
{
flags |= ASS_APPEND;
val = w + len + 3;
}
else
val = w + len + 2;
}
else /* No [ind]=value, just a stray `=' */
{
@@ -324,12 +385,16 @@ assign_array_var_from_string (var, value)
if (integer_p (var))
this_command_name = (char *)NULL; /* no command name for errors */
nval = make_variable_value (var, val);
#if 0
nval = make_variable_value (var, val, flags);
if (var->assign_func)
(*var->assign_func) (var, nval, ind);
else
array_insert (a, ind, nval);
FREE (nval);
#else
bind_array_var_internal (var, ind, val, flags);
#endif
last_ind++;
}
@@ -611,11 +676,7 @@ array_variable_part (s, subp, lenp)
var = find_variable (t);
free (t);
#if 1
return (var == 0 || invisible_p (var)) ? (SHELL_VAR *)0 : var;
#else
return var;
#endif
}
/* Return a string containing the elements in the array and subscript
+6 -6
View File
@@ -1,6 +1,6 @@
/* arrayfunc.h -- declarations for miscellaneous array functions in arrayfunc.c */
/* Copyright (C) 2001 Free Software Foundation, Inc.
/* Copyright (C) 2001-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -27,14 +27,14 @@
extern SHELL_VAR *convert_var_to_array __P((SHELL_VAR *));
extern SHELL_VAR *bind_array_variable __P((char *, arrayind_t, char *));
extern SHELL_VAR *assign_array_element __P((char *, char *));
extern SHELL_VAR *bind_array_variable __P((char *, arrayind_t, char *, int));
extern SHELL_VAR *assign_array_element __P((char *, char *, int));
extern SHELL_VAR *find_or_make_array_variable __P((char *, int));
extern SHELL_VAR *assign_array_from_string __P((char *, char *));
extern SHELL_VAR *assign_array_var_from_word_list __P((SHELL_VAR *, WORD_LIST *));
extern SHELL_VAR *assign_array_var_from_string __P((SHELL_VAR *, char *));
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 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));
+55
View File
@@ -0,0 +1,55 @@
/* arrayfunc.h -- declarations for miscellaneous array functions in arrayfunc.c */
/* Copyright (C) 2001 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 (_ARRAYFUNC_H_)
#define _ARRAYFUNC_H_
/* Must include variables.h before including this file. */
#if defined (ARRAY_VARS)
extern SHELL_VAR *convert_var_to_array __P((SHELL_VAR *));
extern SHELL_VAR *bind_array_variable __P((char *, arrayind_t, char *, int));
extern SHELL_VAR *assign_array_element __P((char *, char *, int));
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 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 arrayind_t array_expand_index __P((char *, int));
extern int valid_array_reference __P((char *));
extern char *array_value __P((char *, int, int *));
extern char *get_array_value __P((char *, int, int *));
extern char *array_keys __P((char *, int));
extern char *array_variable_name __P((char *, char **, int *));
extern SHELL_VAR *array_variable_part __P((char *, char **, int *));
#endif
#endif /* !_ARRAYFUNC_H_ */
+3 -3
View File
@@ -1,7 +1,7 @@
This file is cd.def, from which is created cd.c. It implements the
builtins "cd" and "pwd" in Bash.
Copyright (C) 1987-2003 Free Software Foundation, Inc.
Copyright (C) 1987-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -100,14 +100,14 @@ bindpwd (no_symlinks)
old_anm = array_needs_making;
pwdvar = get_string_value ("PWD");
tvar = bind_variable ("OLDPWD", pwdvar);
tvar = bind_variable ("OLDPWD", pwdvar, 0);
if (old_anm == 0 && array_needs_making && exported_p (tvar))
{
update_export_env_inplace ("OLDPWD=", 7, pwdvar);
array_needs_making = 0;
}
tvar = bind_variable ("PWD", dirname ? dirname : "");
tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
if (old_anm == 0 && array_needs_making && exported_p (tvar))
{
update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
+3 -3
View File
@@ -100,14 +100,14 @@ bindpwd (no_symlinks)
old_anm = array_needs_making;
pwdvar = get_string_value ("PWD");
tvar = bind_variable ("OLDPWD", pwdvar);
tvar = bind_variable ("OLDPWD", pwdvar, 0);
if (old_anm == 0 && array_needs_making && exported_p (tvar))
{
update_export_env_inplace ("OLDPWD=", 7, pwdvar);
array_needs_making = 0;
}
tvar = bind_variable ("PWD", dirname ? dirname : "");
tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
if (old_anm == 0 && array_needs_making && exported_p (tvar))
{
update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
@@ -355,7 +355,7 @@ pwd_builtin (list)
fflush (stdout);
if (ferror (stdout))
{
builtin_error (_("write error: %s"), strerror (errno));
sh_wrerror ();
clearerr (stdout);
return (EXECUTION_FAILURE);
}
+3 -3
View File
@@ -1,7 +1,7 @@
This file is command.def, from which is created command.c.
It implements the builtin "command" in Bash.
Copyright (C) 1987-2002 Free Software Foundation, Inc.
Copyright (C) 1987-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -131,7 +131,7 @@ command_builtin (list)
add_unwind_protect ((Function *)restore_path, old_path);
standard_path = get_standard_path ();
bind_variable ("PATH", standard_path ? standard_path : "");
bind_variable ("PATH", standard_path ? standard_path : "", 0);
FREE (standard_path);
}
@@ -170,7 +170,7 @@ restore_path (var)
{
if (var)
{
bind_variable ("PATH", var);
bind_variable ("PATH", var, 0);
free (var);
}
else
+3 -3
View File
@@ -78,7 +78,7 @@ command_builtin (list)
use_standard_path = 1;
break;
case 'V':
verbose = CDESC_SHORTDESC; /* look in common.h for constants */
verbose = CDESC_SHORTDESC|CDESC_ABSPATH; /* look in common.h for constants */
break;
case 'v':
verbose = CDESC_REUSABLE; /* ditto */
@@ -131,7 +131,7 @@ command_builtin (list)
add_unwind_protect ((Function *)restore_path, old_path);
standard_path = get_standard_path ();
bind_variable ("PATH", standard_path ? standard_path : "");
bind_variable ("PATH", standard_path ? standard_path : "", 0);
FREE (standard_path);
}
@@ -170,7 +170,7 @@ restore_path (var)
{
if (var)
{
bind_variable ("PATH", var);
bind_variable ("PATH", var, 0);
free (var);
}
else
+14 -8
View File
@@ -1,7 +1,7 @@
This file is declare.def, from which is created declare.c.
It implements the builtins "declare" and "local" in Bash.
Copyright (C) 1987-2003 Free Software Foundation, Inc.
Copyright (C) 1987-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -222,18 +222,24 @@ declare_internal (list, local_var)
while (list) /* declare [-afFirx] name [name ...] */
{
char *value, *name;
int offset;
int offset, aflags;
#if defined (ARRAY_VARS)
int making_array_special, compound_array_assign, simple_array_assign;
#endif
name = savestring (list->word->word);
offset = assignment (name, 0);
aflags = 0;
if (offset) /* declare [-afFirx] name=value */
{
name[offset] = '\0';
value = name + offset + 1;
if (name[offset - 1] == '+')
{
aflags |= ASS_APPEND;
name[offset - 1] = '\0';
}
}
else
value = "";
@@ -353,7 +359,7 @@ declare_internal (list, local_var)
var = make_new_array_variable (name);
else
#endif
var = bind_variable (name, "");
var = bind_variable (name, "", 0);
}
/* Cannot use declare +r to turn off readonly attribute. */
@@ -407,23 +413,23 @@ declare_internal (list, local_var)
#if defined (ARRAY_VARS)
if (offset && compound_array_assign)
assign_array_var_from_string (var, value);
assign_array_var_from_string (var, value, aflags);
else if (simple_array_assign && subscript_start)
{
/* declare [-a] name[N]=value */
*subscript_start = '['; /* ] */
var = assign_array_element (name, value);
var = assign_array_element (name, value, 0); /* XXX - not aflags */
*subscript_start = '\0';
}
else if (simple_array_assign)
/* let bind_array_variable take care of this. */
bind_array_variable (name, 0, value);
bind_array_variable (name, 0, value, aflags);
else
#endif
/* bind_variable_value duplicates the essential internals of
bind_variable() */
if (offset)
bind_variable_value (var, value);
bind_variable_value (var, value, aflags);
/* If we found this variable in the temporary environment, as with
`var=value declare -x var', make sure it is treated identically
@@ -443,7 +449,7 @@ declare_internal (list, local_var)
if (tv)
{
tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
tv = bind_variable (var->name, tvalue);
tv = bind_variable (var->name, tvalue, 0);
tv->attributes |= var->attributes & ~att_tempvar;
if (tv->context > 0)
VSETATTR (tv, att_propagate);
+470
View File
@@ -0,0 +1,470 @@
This file is declare.def, from which is created declare.c.
It implements the builtins "declare" and "local" in Bash.
Copyright (C) 1987-2003 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.
$PRODUCES declare.c
$BUILTIN declare
$FUNCTION declare_builtin
$SHORT_DOC declare [-afFirtx] [-p] [name[=value] ...]
Declare variables and/or give them attributes. If no NAMEs are
given, then display the values of variables instead. The -p option
will display the attributes and values of each NAME.
The flags are:
-a to make NAMEs arrays (if supported)
-f to select from among function names only
-F to display function names (and line number and source file name if
debugging) without definitions
-i to make NAMEs have the `integer' attribute
-r to make NAMEs readonly
-t to make NAMEs have the `trace' attribute
-x to make NAMEs export
Variables with the integer attribute have arithmetic evaluation (see
`let') done when the variable is assigned to.
When displaying values of variables, -f displays a function's name
and definition. The -F option restricts the display to function
name only.
Using `+' instead of `-' turns off the given attribute instead. When
used in a function, makes NAMEs local, as with the `local' command.
$END
$BUILTIN typeset
$FUNCTION declare_builtin
$SHORT_DOC typeset [-afFirtx] [-p] name[=value] ...
Obsolete. See `declare'.
$END
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "common.h"
#include "builtext.h"
#include "bashgetopt.h"
extern int array_needs_making;
static int declare_internal __P((register WORD_LIST *, int));
/* Declare or change variable attributes. */
int
declare_builtin (list)
register WORD_LIST *list;
{
return (declare_internal (list, 0));
}
$BUILTIN local
$FUNCTION local_builtin
$SHORT_DOC local name[=value] ...
Create a local variable called NAME, and give it VALUE. LOCAL
can only be used within a function; it makes the variable NAME
have a visible scope restricted to that function and its children.
$END
int
local_builtin (list)
register WORD_LIST *list;
{
if (variable_context)
return (declare_internal (list, 1));
else
{
builtin_error (_("can only be used in a function"));
return (EXECUTION_FAILURE);
}
}
#if defined (ARRAY_VARS)
# define DECLARE_OPTS "+afiprtxF"
#else
# define DECLARE_OPTS "+fiprtxF"
#endif
/* The workhorse function. */
static int
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;
char *t, *subscript_start;
SHELL_VAR *var;
FUNCTION_DEF *shell_fn;
flags_on = flags_off = any_failed = assign_error = pflag = nodefs = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, DECLARE_OPTS)) != EOF)
{
flags = list_opttype == '+' ? &flags_off : &flags_on;
switch (opt)
{
case 'a':
#if defined (ARRAY_VARS)
*flags |= att_array;
#endif
break;
case 'p':
if (local_var == 0)
pflag++;
break;
case 'F':
nodefs++;
*flags |= att_function;
break;
case 'f':
*flags |= att_function;
break;
case 'i':
*flags |= att_integer;
break;
case 'r':
*flags |= att_readonly;
break;
case 't':
*flags |= att_trace;
break;
case 'x':
*flags |= att_exported;
array_needs_making = 1;
break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
/* If there are no more arguments left, then we just want to show
some variables. */
if (list == 0) /* declare -[afFirtx] */
{
/* Show local variables defined at this context level if this is
the `local' builtin. */
if (local_var)
{
register SHELL_VAR **vlist;
register int i;
vlist = all_local_variables ();
if (vlist)
{
for (i = 0; vlist[i]; i++)
print_assignment (vlist[i]);
free (vlist);
}
}
else
{
if (flags_on == 0)
set_builtin ((WORD_LIST *)NULL);
else
set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
}
fflush (stdout);
return (EXECUTION_SUCCESS);
}
if (pflag) /* declare -p [-afFirtx] name [name...] */
{
for (any_failed = 0; list; list = list->next)
{
pflag = show_name_attributes (list->word->word, nodefs);
if (pflag)
{
sh_notfound (list->word->word);
any_failed++;
}
}
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
}
#define NEXT_VARIABLE() free (name); list = list->next; continue
/* There are arguments left, so we are making variables. */
while (list) /* declare [-afFirx] name [name ...] */
{
char *value, *name;
int offset, aflags;
#if defined (ARRAY_VARS)
int making_array_special, compound_array_assign, simple_array_assign;
#endif
name = savestring (list->word->word);
offset = assignment (name, 0);
aflags = 0;
if (offset) /* declare [-afFirx] name=value */
{
name[offset] = '\0';
value = name + offset + 1;
if (name[offset - 1] == '+')
{
aflags |= ASS_APPEND;
name[offset - 1] = '\0';
}
}
else
value = "";
#if defined (ARRAY_VARS)
compound_array_assign = simple_array_assign = 0;
subscript_start = (char *)NULL;
if (t = strchr (name, '[')) /* ] */
{
subscript_start = t;
*t = '\0';
making_array_special = 1;
}
else
making_array_special = 0;
#endif
if (legal_identifier (name) == 0)
{
sh_invalidid (name);
assign_error++;
NEXT_VARIABLE ();
}
/* If VARIABLE_CONTEXT has a non-zero value, then we are executing
inside of a function. This means we should make local variables,
not global ones. */
/* XXX - this has consequences when we're making a local copy of a
variable that was in the temporary environment. Watch out
for this. */
if (variable_context && ((flags_on & att_function) == 0))
{
#if defined (ARRAY_VARS)
if ((flags_on & att_array) || making_array_special)
var = make_local_array_variable (name);
else
#endif
var = make_local_variable (name);
if (var == 0)
{
any_failed++;
NEXT_VARIABLE ();
}
}
else
var = (SHELL_VAR *)NULL;
/* If we are declaring a function, then complain about it in some way.
We don't let people make functions by saying `typeset -f foo=bar'. */
/* There should be a way, however, to let people look at a particular
function definition by saying `typeset -f foo'. */
if (flags_on & att_function)
{
if (offset) /* declare -f [-rix] foo=bar */
{
builtin_error (_("cannot use `-f' to make functions"));
free (name);
return (EXECUTION_FAILURE);
}
else /* declare -f [-rx] name [name...] */
{
var = find_function (name);
if (var)
{
if (readonly_p (var) && (flags_off & att_readonly))
{
builtin_error (_("%s: readonly function"), name);
any_failed++;
NEXT_VARIABLE ();
}
/* declare -[Ff] name [name...] */
if (flags_on == att_function && flags_off == 0)
{
#if defined (DEBUGGER)
if (nodefs && debugging_mode)
{
shell_fn = find_function_def (var->name);
if (shell_fn)
printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file);
else
printf ("%s\n", var->name);
}
else
#endif /* DEBUGGER */
{
t = nodefs ? var->name
: named_function_string (name, function_cell (var), 1);
printf ("%s\n", t);
}
}
else /* declare -[fF] -[rx] name [name...] */
{
VSETATTR (var, flags_on);
VUNSETATTR (var, flags_off);
}
}
else
any_failed++;
NEXT_VARIABLE ();
}
}
else /* declare -[airx] name [name...] */
{
/* Non-null if we just created or fetched a local variable. */
if (var == 0)
var = find_variable (name);
if (var == 0)
{
#if defined (ARRAY_VARS)
if ((flags_on & att_array) || making_array_special)
var = make_new_array_variable (name);
else
#endif
var = bind_variable (name, "", 0);
}
/* Cannot use declare +r to turn off readonly attribute. */
if (readonly_p (var) && (flags_off & att_readonly))
{
sh_readonly (name);
any_failed++;
NEXT_VARIABLE ();
}
/* Cannot use declare to assign value to readonly or noassign
variable. */
if ((readonly_p (var) || noassign_p (var)) && offset)
{
if (readonly_p (var))
sh_readonly (name);
assign_error++;
NEXT_VARIABLE ();
}
#if defined (ARRAY_VARS)
if ((making_array_special || (flags_on & att_array) || array_p (var)) && offset)
{
int vlen;
vlen = STRLEN (value);
#if 0
if (value[0] == '(' && strchr (value, ')'))
#else
if (value[0] == '(' && value[vlen-1] == ')')
#endif
compound_array_assign = 1;
else
simple_array_assign = 1;
}
/* Cannot use declare +a name to remove an array variable. */
if ((flags_off & att_array) && array_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)
var = convert_var_to_array (var);
#endif /* ARRAY_VARS */
VSETATTR (var, flags_on);
VUNSETATTR (var, flags_off);
#if defined (ARRAY_VARS)
if (offset && compound_array_assign)
assign_array_var_from_string (var, value, aflags);
else if (simple_array_assign && subscript_start)
{
/* declare [-a] name[N]=value */
*subscript_start = '['; /* ] */
var = assign_array_element (name, value, 0); /* XXX - not aflags */
*subscript_start = '\0';
}
else if (simple_array_assign)
/* let bind_array_variable take care of this. */
bind_array_variable (name, 0, value, aflags);
else
#endif
/* bind_variable_value duplicates the essential internals of
bind_variable() */
if (offset)
bind_variable_value (var, value, aflags);
/* If we found this variable in the temporary environment, as with
`var=value declare -x var', make sure it is treated identically
to `var=value export var'. Do the same for `declare -r' and
`readonly'. Preserve the attributes, except for att_tempvar. */
/* XXX -- should this create a variable in the global scope, or
modify the local variable flags? ksh93 has it modify the
global scope.
Need to handle case like in set_var_attribute where a temporary
variable is in the same table as the function local vars. */
if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var))
{
SHELL_VAR *tv;
char *tvalue;
tv = find_tempenv_variable (var->name);
if (tv)
{
tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
tv = bind_variable (var->name, tvalue, 0);
tv->attributes |= var->attributes & ~att_tempvar;
if (tv->context > 0)
VSETATTR (tv, att_propagate);
free (tvalue);
}
VSETATTR (var, att_propagate);
}
}
stupidly_hack_special_variables (name);
NEXT_VARIABLE ();
}
return (assign_error ? EX_BADASSIGN
: ((any_failed == 0) ? EXECUTION_SUCCESS
: EXECUTION_FAILURE));
}
+6 -6
View File
@@ -1,7 +1,7 @@
This file is getopts.def, from which is created getopts.c.
It implements the builtin "getopts" in Bash.
Copyright (C) 1987-2002 Free Software Foundation, Inc.
Copyright (C) 1987-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -101,7 +101,7 @@ getopts_bind_variable (name, value)
if (legal_identifier (name))
{
v = bind_variable (name, value);
v = bind_variable (name, value, 0);
return (v && (readonly_p (v) == 0)) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
}
else
@@ -228,7 +228,7 @@ dogetopts (argc, argv)
}
while (n /= 10);
}
bind_variable ("OPTIND", numval + i);
bind_variable ("OPTIND", numval + i, 0);
/* If an error occurred, decide which one it is and set the return
code appropriately. In all cases, the option character in error
@@ -259,7 +259,7 @@ dogetopts (argc, argv)
{
strval[0] = (char)sh_optopt;
strval[1] = '\0';
bind_variable ("OPTARG", strval);
bind_variable ("OPTARG", strval, 0);
}
else
unbind_variable ("OPTARG");
@@ -276,7 +276,7 @@ dogetopts (argc, argv)
strval[0] = (char)sh_optopt;
strval[1] = '\0';
bind_variable ("OPTARG", strval);
bind_variable ("OPTARG", strval, 0);
}
else
{
@@ -286,7 +286,7 @@ dogetopts (argc, argv)
return (ret);
}
bind_variable ("OPTARG", sh_optarg);
bind_variable ("OPTARG", sh_optarg, 0);
strval[0] = (char) ret;
strval[1] = '\0';
+323
View File
@@ -0,0 +1,323 @@
This file is getopts.def, from which is created getopts.c.
It implements the builtin "getopts" in Bash.
Copyright (C) 1987-2002 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.
$PRODUCES getopts.c
$BUILTIN getopts
$FUNCTION getopts_builtin
$SHORT_DOC getopts optstring name [arg]
Getopts is used by shell procedures to parse positional parameters.
OPTSTRING contains the option letters to be recognized; if a letter
is followed by a colon, the option is expected to have an argument,
which should be separated from it by white space.
Each time it is invoked, getopts will place the next option in the
shell variable $name, initializing name if it does not exist, and
the index of the next argument to be processed into the shell
variable OPTIND. OPTIND is initialized to 1 each time the shell or
a shell script is invoked. When an option requires an argument,
getopts places that argument into the shell variable OPTARG.
getopts reports errors in one of two ways. If the first character
of OPTSTRING is a colon, getopts uses silent error reporting. In
this mode, no error messages are printed. If an invalid option is
seen, getopts places the option character found into OPTARG. If a
required argument is not found, getopts places a ':' into NAME and
sets OPTARG to the option character found. If getopts is not in
silent mode, and an invalid option is seen, getopts places '?' into
NAME and unsets OPTARG. If a required argument is not found, a '?'
is placed in NAME, OPTARG is unset, and a diagnostic message is
printed.
If the shell variable OPTERR has the value 0, getopts disables the
printing of error messages, even if the first character of
OPTSTRING is not a colon. OPTERR has the value 1 by default.
Getopts normally parses the positional parameters ($0 - $9), but if
more arguments are given, they are parsed instead.
$END
#include <config.h>
#include <stdio.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../shell.h"
#include "common.h"
#include "bashgetopt.h"
#include "getopt.h"
#define G_EOF -1
#define G_INVALID_OPT -2
#define G_ARG_MISSING -3
extern char *this_command_name;
static int getopts_bind_variable __P((char *, char *));
static int dogetopts __P((int, char **));
/* getopts_reset is magic code for when OPTIND is reset. N is the
value that has just been assigned to OPTIND. */
void
getopts_reset (newind)
int newind;
{
sh_optind = newind;
sh_badopt = 0;
}
static int
getopts_bind_variable (name, value)
char *name, *value;
{
SHELL_VAR *v;
if (legal_identifier (name))
{
v = bind_variable (name, value, 0);
return (v && (readonly_p (v) == 0)) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
}
else
{
sh_invalidid (name);
return (EXECUTION_FAILURE);
}
}
/* Error handling is now performed as specified by Posix.2, draft 11
(identical to that of ksh-88). The special handling is enabled if
the first character of the option string is a colon; this handling
disables diagnostic messages concerning missing option arguments
and invalid option characters. The handling is as follows.
INVALID OPTIONS:
name -> "?"
if (special_error) then
OPTARG = option character found
no error output
else
OPTARG unset
diagnostic message
fi
MISSING OPTION ARGUMENT;
if (special_error) then
name -> ":"
OPTARG = option character found
else
name -> "?"
OPTARG unset
diagnostic message
fi
*/
static int
dogetopts (argc, argv)
int argc;
char **argv;
{
int ret, special_error, old_opterr, i, n;
char strval[2], numval[16];
char *optstr; /* list of options */
char *name; /* variable to get flag val */
char *t;
if (argc < 3)
{
builtin_usage ();
return (EX_USAGE);
}
/* argv[0] is "getopts". */
optstr = argv[1];
name = argv[2];
argc -= 2;
argv += 2;
special_error = optstr[0] == ':';
if (special_error)
{
old_opterr = sh_opterr;
optstr++;
sh_opterr = 0; /* suppress diagnostic messages */
}
if (argc > 1)
{
sh_getopt_restore_state (argv);
t = argv[0];
argv[0] = dollar_vars[0];
ret = sh_getopt (argc, argv, optstr);
argv[0] = t;
}
else if (rest_of_args == (WORD_LIST *)NULL)
{
for (i = 0; i < 10 && dollar_vars[i]; i++)
;
sh_getopt_restore_state (dollar_vars);
ret = sh_getopt (i, dollar_vars, optstr);
}
else
{
register WORD_LIST *words;
char **v;
for (i = 0; i < 10 && dollar_vars[i]; i++)
;
for (words = rest_of_args; words; words = words->next, i++)
;
v = strvec_create (i + 1);
for (i = 0; i < 10 && dollar_vars[i]; i++)
v[i] = dollar_vars[i];
for (words = rest_of_args; words; words = words->next, i++)
v[i] = words->word->word;
v[i] = (char *)NULL;
sh_getopt_restore_state (v);
ret = sh_getopt (i, v, optstr);
free (v);
}
if (special_error)
sh_opterr = old_opterr;
/* Set the OPTIND variable in any case, to handle "--" skipping. It's
highly unlikely that 14 digits will be too few. */
if (sh_optind < 10)
{
numval[14] = sh_optind + '0';
numval[15] = '\0';
i = 14;
}
else
{
numval[i = 15] = '\0';
n = sh_optind;
do
{
numval[--i] = (n % 10) + '0';
}
while (n /= 10);
}
bind_variable ("OPTIND", numval + i, 0);
/* If an error occurred, decide which one it is and set the return
code appropriately. In all cases, the option character in error
is in OPTOPT. If an invalid option was encountered, OPTARG is
NULL. If a required option argument was missing, OPTARG points
to a NULL string (that is, sh_optarg[0] == 0). */
if (ret == '?')
{
if (sh_optarg == NULL)
ret = G_INVALID_OPT;
else if (sh_optarg[0] == '\0')
ret = G_ARG_MISSING;
}
if (ret == G_EOF)
{
unbind_variable ("OPTARG");
getopts_bind_variable (name, "?");
return (EXECUTION_FAILURE);
}
if (ret == G_INVALID_OPT)
{
/* Invalid option encountered. */
ret = getopts_bind_variable (name, "?");
if (special_error)
{
strval[0] = (char)sh_optopt;
strval[1] = '\0';
bind_variable ("OPTARG", strval, 0);
}
else
unbind_variable ("OPTARG");
return (ret);
}
if (ret == G_ARG_MISSING)
{
/* Required argument missing. */
if (special_error)
{
ret = getopts_bind_variable (name, ":");
strval[0] = (char)sh_optopt;
strval[1] = '\0';
bind_variable ("OPTARG", strval, 0);
}
else
{
ret = getopts_bind_variable (name, "?");
unbind_variable ("OPTARG");
}
return (ret);
}
bind_variable ("OPTARG", sh_optarg, 0);
strval[0] = (char) ret;
strval[1] = '\0';
return (getopts_bind_variable (name, strval));
}
/* The getopts builtin. Build an argv, and call dogetopts with it. */
int
getopts_builtin (list)
WORD_LIST *list;
{
char **av;
int ac, ret;
if (list == 0)
{
builtin_usage ();
return EX_USAGE;
}
reset_internal_getopt ();
if (internal_getopt (list, "") != -1)
{
builtin_usage ();
return (EX_USAGE);
}
list = loptend;
av = make_builtin_argv (list, &ac);
ret = dogetopts (ac, av);
free ((char *)av);
return (ret);
}
+1 -1
View File
@@ -1,7 +1,7 @@
This file is pushd.def, from which is created pushd.c. It implements the
builtins "pushd", "popd", and "dirs" in Bash.
Copyright (C) 1987-2003 Free Software Foundation, Inc.
Copyright (C) 1987-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+8 -3
View File
@@ -152,12 +152,17 @@ pushd_builtin (list)
WORD_LIST *list;
{
char *temp, *current_directory, *top;
int j, flags;
int j, flags, skipopt;
intmax_t num;
char direction;
if (list && list->word && ISOPTION (list->word->word, '-'))
list = list->next;
{
list = list->next;
skipopt = 1;
}
else
skipopt = 0;
/* If there is no argument list then switch current and
top of list. */
@@ -181,7 +186,7 @@ pushd_builtin (list)
return j;
}
for (flags = 0; list; list = list->next)
for (flags = 0; skipopt == 0 && list; list = list->next)
{
if (ISOPTION (list->word->word, 'n'))
{
+6 -6
View File
@@ -515,7 +515,7 @@ read_builtin (list)
if (alist)
{
word_list_remove_quoted_nulls (alist);
assign_array_var_from_word_list (var, alist);
assign_array_var_from_word_list (var, alist, 0);
dispose_words (alist);
}
xfree (input_string);
@@ -544,11 +544,11 @@ read_builtin (list)
if (saw_escape)
{
t = dequote_string (input_string);
var = bind_variable ("REPLY", t);
var = bind_variable ("REPLY", t, 0);
free (t);
}
else
var = bind_variable ("REPLY", input_string);
var = bind_variable ("REPLY", input_string, 0);
VUNSETATTR (var, att_invisible);
free (input_string);
@@ -654,11 +654,11 @@ bind_read_variable (name, value)
{
#if defined (ARRAY_VARS)
if (valid_array_reference (name) == 0)
return (bind_variable (name, value));
return (bind_variable (name, value, 0));
else
return (assign_array_element (name, value));
return (assign_array_element (name, value, 0));
#else /* !ARRAY_VARS */
return bind_variable (name, value);
return bind_variable (name, value, 0);
#endif /* !ARRAY_VARS */
}
+736
View File
@@ -0,0 +1,736 @@
This file is read.def, from which is created read.c.
It implements the builtin "read" in Bash.
Copyright (C) 1987-2004 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.
$PRODUCES read.c
$BUILTIN read
$FUNCTION read_builtin
$SHORT_DOC read [-ers] [-u fd] [-t timeout] [-p prompt] [-a array] [-n nchars] [-d delim] [name ...]
One line is read from the standard input, or from file descriptor FD if the
-u option is supplied, and the first word is assigned to the first NAME,
the second word to the second NAME, and so on, with leftover words assigned
to the last NAME. Only the characters found in $IFS are recognized as word
delimiters. If no NAMEs are supplied, the line read is stored in the REPLY
variable. If the -r option is given, this signifies `raw' input, and
backslash escaping is disabled. The -d option causes read to continue
until the first character of DELIM is read, rather than newline. If the -p
option is supplied, the string PROMPT is output without a trailing newline
before attempting to read. If -a is supplied, the words read are assigned
to sequential indices of ARRAY, starting at zero. If -e is supplied and
the shell is interactive, readline is used to obtain the line. If -n is
supplied with a non-zero NCHARS argument, read returns after NCHARS
characters have been read. The -s option causes input coming from a
terminal to not be echoed.
The -t option causes read to time out and return failure if a complete line
of input is not read within TIMEOUT seconds. If the TMOUT variable is set,
its value is the default timeout. The return code is zero, unless end-of-file
is encountered, read times out, or an invalid file descriptor is supplied as
the argument to -u.
$END
#include <config.h>
#include "bashtypes.h"
#include "posixstat.h"
#include <stdio.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <signal.h>
#include <errno.h>
#ifdef __CYGWIN__
# include <fcntl.h>
# include <io.h>
#endif
#include "../bashintl.h"
#include "../shell.h"
#include "common.h"
#include "bashgetopt.h"
#include <shtty.h>
#if defined (READLINE)
#include "../bashline.h"
#include <readline/readline.h>
#endif
#if !defined(errno)
extern int errno;
#endif
extern int interrupt_immediately;
#if defined (READLINE)
static char *edit_line __P((char *));
static void set_eol_delim __P((int));
static void reset_eol_delim __P((char *));
#endif
static SHELL_VAR *bind_read_variable __P((char *, char *));
static sighandler sigalrm __P((int));
static void reset_alarm __P((void));
static procenv_t alrmbuf;
static SigHandler *old_alrm;
static unsigned char delim;
static sighandler
sigalrm (s)
int s;
{
longjmp (alrmbuf, 1);
}
static void
reset_alarm ()
{
set_signal_handler (SIGALRM, old_alrm);
alarm (0);
}
/* Read the value of the shell variables whose names follow.
The reading is done from the current input stream, whatever
that may be. Successive words of the input line are assigned
to the variables mentioned in LIST. The last variable in LIST
gets the remainder of the words on the line. If no variables
are mentioned in LIST, then the default variable is $REPLY. */
int
read_builtin (list)
WORD_LIST *list;
{
register char *varname;
int size, i, pass_next, saw_escape, eof, opt, retval, code;
int input_is_tty, input_is_pipe, unbuffered_read;
int raw, edit, nchars, silent, have_timeout, fd;
unsigned int tmout;
intmax_t intval;
char c;
char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname;
char *e, *t, *t1;
struct stat tsb;
SHELL_VAR *var;
#if defined (ARRAY_VARS)
WORD_LIST *alist;
#endif
#if defined (READLINE)
char *rlbuf;
int rlind;
#endif
USE_VAR(size);
USE_VAR(i);
USE_VAR(pass_next);
USE_VAR(saw_escape);
USE_VAR(input_is_pipe);
/* USE_VAR(raw); */
USE_VAR(edit);
USE_VAR(tmout);
USE_VAR(nchars);
USE_VAR(silent);
USE_VAR(ifs_chars);
USE_VAR(prompt);
USE_VAR(arrayname);
#if defined (READLINE)
USE_VAR(rlbuf);
USE_VAR(rlind);
#endif
USE_VAR(list);
i = 0; /* Index into the string that we are reading. */
raw = edit = 0; /* Not reading raw input by default. */
silent = 0;
arrayname = prompt = (char *)NULL;
fd = 0; /* file descriptor to read from */
#if defined (READLINE)
rlbuf = (char *)0;
rlind = 0;
#endif
tmout = 0; /* no timeout */
nchars = input_is_tty = input_is_pipe = unbuffered_read = have_timeout = 0;
delim = '\n'; /* read until newline */
reset_internal_getopt ();
while ((opt = internal_getopt (list, "ersa:d:n:p:t:u:")) != -1)
{
switch (opt)
{
case 'r':
raw = 1;
break;
case 'p':
prompt = list_optarg;
break;
case 's':
silent = 1;
break;
case 'e':
#if defined (READLINE)
edit = 1;
#endif
break;
#if defined (ARRAY_VARS)
case 'a':
arrayname = list_optarg;
break;
#endif
case 't':
code = legal_number (list_optarg, &intval);
if (code == 0 || intval < 0 || intval != (unsigned int)intval)
{
builtin_error (_("%s: invalid timeout specification"), list_optarg);
return (EXECUTION_FAILURE);
}
else
{
have_timeout = 1;
tmout = intval;
}
break;
case 'n':
code = legal_number (list_optarg, &intval);
if (code == 0 || intval < 0 || intval != (int)intval)
{
sh_invalidnum (list_optarg);
return (EXECUTION_FAILURE);
}
else
nchars = intval;
break;
case 'u':
code = legal_number (list_optarg, &intval);
if (code == 0 || intval < 0 || intval != (int)intval)
{
builtin_error (_("%s: invalid file descriptor specification"), list_optarg);
return (EXECUTION_FAILURE);
}
else
fd = intval;
if (sh_validfd (fd) == 0)
{
builtin_error (_("%d: invalid file descriptor: %s"), fd, strerror (errno));
return (EXECUTION_FAILURE);
}
break;
case 'd':
delim = *list_optarg;
break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
/* `read -t 0 var' returns failure immediately. XXX - should it test
whether input is available with select/FIONREAD, and fail if those
are unavailable? */
if (have_timeout && tmout == 0)
return (EXECUTION_FAILURE);
/* IF IFS is unset, we use the default of " \t\n". */
ifs_chars = getifs ();
if (ifs_chars == 0) /* XXX - shouldn't happen */
ifs_chars = "";
input_string = (char *)xmalloc (size = 112); /* XXX was 128 */
/* $TMOUT, if set, is the default timeout for read. */
if (have_timeout == 0 && (e = get_string_value ("TMOUT")))
{
code = legal_number (e, &intval);
if (code == 0 || intval < 0 || intval != (unsigned int)intval)
tmout = 0;
else
tmout = intval;
}
begin_unwind_frame ("read_builtin");
input_is_tty = isatty (fd);
if (input_is_tty == 0)
#ifndef __CYGWIN__
input_is_pipe = (lseek (0, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
#else
input_is_pipe = 1;
#endif
/* If the -p, -e or -s flags were given, but input is not coming from the
terminal, turn them off. */
if ((prompt || edit || silent) && input_is_tty == 0)
{
prompt = (char *)NULL;
edit = silent = 0;
}
#if defined (READLINE)
if (edit)
add_unwind_protect (xfree, rlbuf);
#endif
if (prompt && edit == 0)
{
fprintf (stderr, "%s", prompt);
fflush (stderr);
}
pass_next = 0; /* Non-zero signifies last char was backslash. */
saw_escape = 0; /* Non-zero signifies that we saw an escape char */
if (tmout > 0)
{
/* Turn off the timeout if stdin is a regular file (e.g. from
input redirection). */
if ((fstat (fd, &tsb) < 0) || S_ISREG (tsb.st_mode))
tmout = 0;
}
if (tmout > 0)
{
code = setjmp (alrmbuf);
if (code)
{
run_unwind_frame ("read_builtin");
return (EXECUTION_FAILURE);
}
old_alrm = set_signal_handler (SIGALRM, sigalrm);
add_unwind_protect (reset_alarm, (char *)NULL);
alarm (tmout);
}
/* If we've been asked to read only NCHARS chars, or we're using some
character other than newline to terminate the line, do the right
thing to readline or the tty. */
if (nchars > 0 || delim != '\n')
{
#if defined (READLINE)
if (edit)
{
if (nchars > 0)
{
unwind_protect_int (rl_num_chars_to_read);
rl_num_chars_to_read = nchars;
}
if (delim != '\n')
{
set_eol_delim (delim);
add_unwind_protect (reset_eol_delim, (char *)NULL);
}
}
else
#endif
if (input_is_tty)
{
ttsave ();
if (silent)
ttcbreak ();
else
ttonechar ();
add_unwind_protect ((Function *)ttrestore, (char *)NULL);
}
}
else if (silent) /* turn off echo but leave term in canonical mode */
{
ttsave ();
ttnoecho ();
add_unwind_protect ((Function *)ttrestore, (char *)NULL);
}
/* This *must* be the top unwind-protect on the stack, so the manipulation
of the unwind-protect stack after the realloc() works right. */
add_unwind_protect (xfree, input_string);
interrupt_immediately++;
unbuffered_read = (nchars > 0) || (delim != '\n') || input_is_pipe;
#if defined (__CYGWIN__) && defined (O_TEXT)
setmode (0, O_TEXT);
#endif
for (eof = retval = 0;;)
{
#if defined (READLINE)
if (edit)
{
if (rlbuf && rlbuf[rlind] == '\0')
{
xfree (rlbuf);
rlbuf = (char *)0;
}
if (rlbuf == 0)
{
rlbuf = edit_line (prompt ? prompt : "");
rlind = 0;
}
if (rlbuf == 0)
{
eof = 1;
break;
}
c = rlbuf[rlind++];
}
else
{
#endif
if (unbuffered_read)
retval = zread (fd, &c, 1);
else
retval = zreadc (fd, &c);
if (retval <= 0)
{
eof = 1;
break;
}
#if defined (READLINE)
}
#endif
if (i + 2 >= size)
{
input_string = (char *)xrealloc (input_string, size += 128);
remove_unwind_protect ();
add_unwind_protect (xfree, input_string);
}
/* If the next character is to be accepted verbatim, a backslash
newline pair still disappears from the input. */
if (pass_next)
{
if (c == '\n')
i--; /* back up over the CTLESC */
else
input_string[i++] = c;
pass_next = 0;
continue;
}
if (c == '\\' && raw == 0)
{
pass_next++;
saw_escape++;
input_string[i++] = CTLESC;
continue;
}
if ((unsigned char)c == delim)
break;
if (c == CTLESC || c == CTLNUL)
{
saw_escape++;
input_string[i++] = CTLESC;
}
input_string[i++] = c;
if (nchars > 0 && i >= nchars)
break;
}
input_string[i] = '\0';
#if 1
if (retval < 0)
{
builtin_error (_("read error: %d: %s"), fd, strerror (errno));
return (EXECUTION_FAILURE);
}
#endif
if (tmout > 0)
reset_alarm ();
if (nchars > 0 || delim != '\n')
{
#if defined (READLINE)
if (edit)
{
if (nchars > 0)
rl_num_chars_to_read = 0;
if (delim != '\n')
reset_eol_delim ((char *)NULL);
}
else
#endif
if (input_is_tty)
ttrestore ();
}
else if (silent)
ttrestore ();
if (unbuffered_read == 0)
zsyncfd (fd);
interrupt_immediately--;
discard_unwind_frame ("read_builtin");
retval = eof ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
#if defined (ARRAY_VARS)
/* If -a was given, take the string read, break it into a list of words,
an assign them to `arrayname' in turn. */
if (arrayname)
{
if (legal_identifier (arrayname) == 0)
{
sh_invalidid (arrayname);
xfree (input_string);
return (EXECUTION_FAILURE);
}
var = find_or_make_array_variable (arrayname, 1);
if (var == 0)
return EXECUTION_FAILURE; /* readonly or noassign */
array_flush (array_cell (var));
alist = list_string (input_string, ifs_chars, 0);
if (alist)
{
word_list_remove_quoted_nulls (alist);
assign_array_var_from_word_list (var, alist, 0);
dispose_words (alist);
}
xfree (input_string);
return (retval);
}
#endif /* ARRAY_VARS */
/* If there are no variables, save the text of the line read to the
variable $REPLY. ksh93 strips leading and trailing IFS whitespace,
so that `read x ; echo "$x"' and `read ; echo "$REPLY"' behave the
same way, but I believe that the difference in behaviors is useful
enough to not do it. Without the bash behavior, there is no way
to read a line completely without interpretation or modification
unless you mess with $IFS (e.g., setting it to the empty string).
If you disagree, change the occurrences of `#if 0' to `#if 1' below. */
if (list == 0)
{
#if 0
orig_input_string = input_string;
for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++)
;
input_string = t;
input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape);
#endif
if (saw_escape)
{
t = dequote_string (input_string);
var = bind_variable ("REPLY", t);
free (t);
}
else
var = bind_variable ("REPLY", input_string);
VUNSETATTR (var, att_invisible);
free (input_string);
return (retval);
}
/* This code implements the Posix.2 spec for splitting the words
read and assigning them to variables. */
orig_input_string = input_string;
/* Remove IFS white space at the beginning of the input string. If
$IFS is null, no field splitting is performed. */
for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++)
;
input_string = t;
for (; list->next; list = list->next)
{
varname = list->word->word;
#if defined (ARRAY_VARS)
if (legal_identifier (varname) == 0 && valid_array_reference (varname) == 0)
#else
if (legal_identifier (varname) == 0)
#endif
{
sh_invalidid (varname);
xfree (orig_input_string);
return (EXECUTION_FAILURE);
}
/* If there are more variables than words read from the input,
the remaining variables are set to the empty string. */
if (*input_string)
{
/* This call updates INPUT_STRING. */
t = get_word_from_string (&input_string, ifs_chars, &e);
if (t)
*e = '\0';
/* Don't bother to remove the CTLESC unless we added one
somewhere while reading the string. */
if (t && saw_escape)
{
t1 = dequote_string (t);
var = bind_read_variable (varname, t1);
xfree (t1);
}
else
var = bind_read_variable (varname, t);
}
else
{
t = (char *)0;
var = bind_read_variable (varname, "");
}
FREE (t);
if (var == 0)
{
xfree (orig_input_string);
return (EXECUTION_FAILURE);
}
stupidly_hack_special_variables (varname);
VUNSETATTR (var, att_invisible);
}
/* Now assign the rest of the line to the last variable argument. */
#if defined (ARRAY_VARS)
if (legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word) == 0)
#else
if (legal_identifier (list->word->word) == 0)
#endif
{
sh_invalidid (list->word->word);
xfree (orig_input_string);
return (EXECUTION_FAILURE);
}
/* This has to be done this way rather than using string_list
and list_string because Posix.2 says that the last variable gets the
remaining words and their intervening separators. */
input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape);
if (saw_escape)
{
t = dequote_string (input_string);
var = bind_read_variable (list->word->word, t);
xfree (t);
}
else
var = bind_read_variable (list->word->word, input_string);
stupidly_hack_special_variables (list->word->word);
if (var)
VUNSETATTR (var, att_invisible);
xfree (orig_input_string);
return (retval);
}
static SHELL_VAR *
bind_read_variable (name, value)
char *name, *value;
{
#if defined (ARRAY_VARS)
if (valid_array_reference (name) == 0)
return (bind_variable (name, value));
else
return (assign_array_element (name, value, 0));
#else /* !ARRAY_VARS */
return bind_variable (name, value);
#endif /* !ARRAY_VARS */
}
#if defined (READLINE)
static rl_completion_func_t *old_attempted_completion_function;
static char *
edit_line (p)
char *p;
{
char *ret;
int len;
if (!bash_readline_initialized)
initialize_readline ();
old_attempted_completion_function = rl_attempted_completion_function;
rl_attempted_completion_function = (rl_completion_func_t *)NULL;
ret = readline (p);
rl_attempted_completion_function = old_attempted_completion_function;
if (ret == 0)
return ret;
len = strlen (ret);
ret = (char *)xrealloc (ret, len + 2);
ret[len++] = delim;
ret[len] = '\0';
return ret;
}
static int old_delim_ctype;
static rl_command_func_t *old_delim_func;
static int old_newline_ctype;
static rl_command_func_t *old_newline_func;
static unsigned char delim_char;
static void
set_eol_delim (c)
int c;
{
Keymap cmap;
if (bash_readline_initialized == 0)
initialize_readline ();
cmap = rl_get_keymap ();
/* Change newline to self-insert */
old_newline_ctype = cmap[RETURN].type;
old_newline_func = cmap[RETURN].function;
cmap[RETURN].type = ISFUNC;
cmap[RETURN].function = rl_insert;
/* Bind the delimiter character to accept-line. */
old_delim_ctype = cmap[c].type;
old_delim_func = cmap[c].function;
cmap[c].type = ISFUNC;
cmap[c].function = rl_newline;
delim_char = c;
}
static void
reset_eol_delim (cp)
char *cp;
{
Keymap cmap;
cmap = rl_get_keymap ();
cmap[RETURN].type = old_newline_ctype;
cmap[RETURN].function = old_newline_func;
cmap[delim_char].type = old_delim_ctype;
cmap[delim_char].function = old_delim_func;
}
#endif
+4 -4
View File
@@ -1,7 +1,7 @@
This file is set.def, from which is created set.c.
It implements the "set" and "unset" builtins in Bash.
Copyright (C) 1987-2002 Free Software Foundation, Inc.
Copyright (C) 1987-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -311,7 +311,7 @@ set_ignoreeof (on_or_off, option_name)
ignoreeof = on_or_off == FLAG_ON;
unbind_variable ("ignoreeof");
if (ignoreeof)
bind_variable ("IGNOREEOF", "10");
bind_variable ("IGNOREEOF", "10", 0);
else
unbind_variable ("IGNOREEOF");
sv_ignoreeof ("IGNOREEOF");
@@ -327,7 +327,7 @@ set_posix_mode (on_or_off, option_name)
if (posixly_correct == 0)
unbind_variable ("POSIXLY_CORRECT");
else
bind_variable ("POSIXLY_CORRECT", "y");
bind_variable ("POSIXLY_CORRECT", "y", 0);
sv_strict_posix ("POSIXLY_CORRECT");
return (0);
}
@@ -503,7 +503,7 @@ set_shellopts ()
else
exported = 0;
v = bind_variable ("SHELLOPTS", value);
v = bind_variable ("SHELLOPTS", value, 0);
/* Turn the read-only attribute back on, and turn off the export attribute
if it was set implicitly by mark_modified_vars and SHELLOPTS was not
+829
View File
@@ -0,0 +1,829 @@
This file is set.def, from which is created set.c.
It implements the "set" and "unset" builtins in Bash.
Copyright (C) 1987-2002 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.
$PRODUCES set.c
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../flags.h"
#include "common.h"
#include "bashgetopt.h"
#if defined (READLINE)
# include "../input.h"
# include "../bashline.h"
# include <readline/readline.h>
#endif
#if defined (HISTORY)
# include "../bashhist.h"
#endif
extern int posixly_correct, ignoreeof, eof_encountered_limit;
#if defined (HISTORY)
extern int dont_save_function_defs;
#endif
#if defined (READLINE)
extern int no_line_editing;
#endif /* READLINE */
$BUILTIN set
$FUNCTION set_builtin
$SHORT_DOC set [--abefhkmnptuvxBCHP] [-o option] [arg ...]
-a Mark variables which are modified or created for export.
-b Notify of job termination immediately.
-e Exit immediately if a command exits with a non-zero status.
-f Disable file name generation (globbing).
-h Remember the location of commands as they are looked up.
-k All assignment arguments are placed in the environment for a
command, not just those that precede the command name.
-m Job control is enabled.
-n Read commands but do not execute them.
-o option-name
Set the variable corresponding to option-name:
allexport same as -a
braceexpand same as -B
#if defined (READLINE)
emacs use an emacs-style line editing interface
#endif /* READLINE */
errexit same as -e
errtrace same as -E
functrace same as -T
hashall same as -h
#if defined (BANG_HISTORY)
histexpand same as -H
#endif /* BANG_HISTORY */
#if defined (HISTORY)
history enable command history
#endif
ignoreeof the shell will not exit upon reading EOF
interactive-comments
allow comments to appear in interactive commands
keyword same as -k
monitor same as -m
noclobber same as -C
noexec same as -n
noglob same as -f
nolog currently accepted but ignored
notify same as -b
nounset same as -u
onecmd same as -t
physical same as -P
pipefail the return value of a pipeline is the status of
the last command to exit with a non-zero status,
or zero if no command exited with a non-zero status
posix change the behavior of bash where the default
operation differs from the 1003.2 standard to
match the standard
privileged same as -p
verbose same as -v
#if defined (READLINE)
vi use a vi-style line editing interface
#endif /* READLINE */
xtrace same as -x
-p Turned on whenever the real and effective user ids do not match.
Disables processing of the $ENV file and importing of shell
functions. Turning this option off causes the effective uid and
gid to be set to the real uid and gid.
-t Exit after reading and executing one command.
-u Treat unset variables as an error when substituting.
-v Print shell input lines as they are read.
-x Print commands and their arguments as they are executed.
#if defined (BRACE_EXPANSION)
-B the shell will perform brace expansion
#endif /* BRACE_EXPANSION */
-C If set, disallow existing regular files to be overwritten
by redirection of output.
-E If set, the ERR trap is inherited by shell functions.
#if defined (BANG_HISTORY)
-H Enable ! style history substitution. This flag is on
by default.
#endif /* BANG_HISTORY */
-P If set, do not follow symbolic links when executing commands
such as cd which change the current directory.
-T If set, the DEBUG trap is inherited by shell functions.
Using + rather than - causes these flags to be turned off. The
flags can also be used upon invocation of the shell. The current
set of flags may be found in $-. The remaining n ARGs are positional
parameters and are assigned, in order, to $1, $2, .. $n. If no
ARGs are given, all shell variables are printed.
$END
typedef int setopt_set_func_t __P((int, char *));
typedef int setopt_get_func_t __P((char *));
static void print_minus_o_option __P((char *, int, int));
static void print_all_shell_variables __P((void));
static int set_ignoreeof __P((int, char *));
static int set_posix_mode __P((int, char *));
#if defined (READLINE)
static int set_edit_mode __P((int, char *));
static int get_edit_mode __P((char *));
#endif
#if defined (HISTORY)
static int bash_set_history __P((int, char *));
#endif
static char *on = "on";
static char *off = "off";
/* A struct used to match long options for set -o to the corresponding
option letter or internal variable. The functions can be called to
dynamically generate values. */
struct {
char *name;
int letter;
int *variable;
setopt_set_func_t *set_func;
setopt_get_func_t *get_func;
} o_options[] = {
{ "allexport", 'a', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
#if defined (BRACE_EXPANSION)
{ "braceexpand",'B', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
#endif
#if defined (READLINE)
{ "emacs", '\0', (int *)NULL, set_edit_mode, get_edit_mode },
#endif
{ "errexit", 'e', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
{ "errtrace", 'E', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
{ "functrace", 'T', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
{ "hashall", 'h', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
#if defined (BANG_HISTORY)
{ "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
#endif /* BANG_HISTORY */
#if defined (HISTORY)
{ "history", '\0', &remember_on_history, bash_set_history, (setopt_get_func_t *)NULL },
#endif
{ "ignoreeof", '\0', &ignoreeof, set_ignoreeof, (setopt_get_func_t *)NULL },
{ "interactive-comments", '\0', &interactive_comments, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
{ "keyword", 'k', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
{ "monitor", 'm', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
{ "noclobber", 'C', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
{ "noexec", 'n', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
{ "noglob", 'f', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
#if defined (HISTORY)
{ "nolog", '\0', &dont_save_function_defs, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
#endif
#if defined (JOB_CONTROL)
{ "notify", 'b', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
#endif /* JOB_CONTROL */
{ "nounset", 'u', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
{ "onecmd", 't', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
{ "physical", 'P', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
{ "pipefail", '\0', &pipefail_opt, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
{ "posix", '\0', &posixly_correct, set_posix_mode, (setopt_get_func_t *)NULL },
{ "privileged", 'p', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
{ "verbose", 'v', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
#if defined (READLINE)
{ "vi", '\0', (int *)NULL, set_edit_mode, get_edit_mode },
#endif
{ "xtrace", 'x', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
{(char *)NULL, 0 , (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
};
#define N_O_OPTIONS (sizeof (o_options) / sizeof (o_options[0]))
#define GET_BINARY_O_OPTION_VALUE(i, name) \
((o_options[i].get_func) ? (*o_options[i].get_func) (name) \
: (*o_options[i].variable))
#define SET_BINARY_O_OPTION_VALUE(i, onoff, name) \
((o_options[i].set_func) ? (*o_options[i].set_func) (onoff, name) \
: (*o_options[i].variable = (onoff == FLAG_ON)))
int
minus_o_option_value (name)
char *name;
{
register int i;
int *on_or_off;
for (i = 0; o_options[i].name; i++)
{
if (STREQ (name, o_options[i].name))
{
if (o_options[i].letter)
{
on_or_off = find_flag (o_options[i].letter);
return ((on_or_off == FLAG_UNKNOWN) ? -1 : *on_or_off);
}
else
return (GET_BINARY_O_OPTION_VALUE (i, name));
}
}
return (-1);
}
#define MINUS_O_FORMAT "%-15s\t%s\n"
static void
print_minus_o_option (name, value, pflag)
char *name;
int value, pflag;
{
if (pflag == 0)
printf (MINUS_O_FORMAT, name, value ? on : off);
else
printf ("set %co %s\n", value ? '-' : '+', name);
}
void
list_minus_o_opts (mode, reusable)
int mode, reusable;
{
register int i;
int *on_or_off, value;
for (i = 0; o_options[i].name; i++)
{
if (o_options[i].letter)
{
value = 0;
on_or_off = find_flag (o_options[i].letter);
if (on_or_off == FLAG_UNKNOWN)
on_or_off = &value;
if (mode == -1 || mode == *on_or_off)
print_minus_o_option (o_options[i].name, *on_or_off, reusable);
}
else
{
value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
if (mode == -1 || mode == value)
print_minus_o_option (o_options[i].name, value, reusable);
}
}
}
char **
get_minus_o_opts ()
{
char **ret;
int i;
ret = strvec_create (N_O_OPTIONS + 1);
for (i = 0; o_options[i].name; i++)
ret[i] = o_options[i].name;
ret[i] = (char *)NULL;
return ret;
}
static int
set_ignoreeof (on_or_off, option_name)
int on_or_off;
char *option_name;
{
ignoreeof = on_or_off == FLAG_ON;
unbind_variable ("ignoreeof");
if (ignoreeof)
bind_variable ("IGNOREEOF", "10", 0);
else
unbind_variable ("IGNOREEOF");
sv_ignoreeof ("IGNOREEOF");
return 0;
}
static int
set_posix_mode (on_or_off, option_name)
int on_or_off;
char *option_name;
{
posixly_correct = on_or_off == FLAG_ON;
if (posixly_correct == 0)
unbind_variable ("POSIXLY_CORRECT");
else
bind_variable ("POSIXLY_CORRECT", "y", 0);
sv_strict_posix ("POSIXLY_CORRECT");
return (0);
}
#if defined (READLINE)
/* Magic. This code `knows' how readline handles rl_editing_mode. */
static int
set_edit_mode (on_or_off, option_name)
int on_or_off;
char *option_name;
{
int isemacs;
if (on_or_off == FLAG_ON)
{
rl_variable_bind ("editing-mode", option_name);
if (interactive)
with_input_from_stdin ();
no_line_editing = 0;
}
else
{
isemacs = rl_editing_mode == 1;
if ((isemacs && *option_name == 'e') || (!isemacs && *option_name == 'v'))
{
if (interactive)
with_input_from_stream (stdin, "stdin");
no_line_editing = 1;
}
}
return 1-no_line_editing;
}
static int
get_edit_mode (name)
char *name;
{
return (*name == 'e' ? no_line_editing == 0 && rl_editing_mode == 1
: no_line_editing == 0 && rl_editing_mode == 0);
}
#endif /* READLINE */
#if defined (HISTORY)
static int
bash_set_history (on_or_off, option_name)
int on_or_off;
char *option_name;
{
if (on_or_off == FLAG_ON)
{
bash_history_enable ();
if (history_lines_this_session == 0)
load_history ();
}
else
bash_history_disable ();
return (1 - remember_on_history);
}
#endif
int
set_minus_o_option (on_or_off, option_name)
int on_or_off;
char *option_name;
{
register int i;
for (i = 0; o_options[i].name; i++)
{
if (STREQ (option_name, o_options[i].name))
{
if (o_options[i].letter == 0)
{
SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name);
return (EXECUTION_SUCCESS);
}
else
{
if (change_flag (o_options[i].letter, on_or_off) == FLAG_ERROR)
{
sh_invalidoptname (option_name);
return (EXECUTION_FAILURE);
}
else
return (EXECUTION_SUCCESS);
}
}
}
sh_invalidoptname (option_name);
return (EXECUTION_FAILURE);
}
static void
print_all_shell_variables ()
{
SHELL_VAR **vars;
vars = all_shell_variables ();
if (vars)
{
print_var_list (vars);
free (vars);
}
/* POSIX.2 does not allow function names and definitions to be output when
`set' is invoked without options (PASC Interp #202). */
if (posixly_correct == 0)
{
vars = all_shell_functions ();
if (vars)
{
print_func_list (vars);
free (vars);
}
}
}
void
set_shellopts ()
{
char *value;
char tflag[N_O_OPTIONS];
int vsize, i, vptr, *ip, exported;
SHELL_VAR *v;
for (vsize = i = 0; o_options[i].name; i++)
{
tflag[i] = 0;
if (o_options[i].letter)
{
ip = find_flag (o_options[i].letter);
if (ip && *ip)
{
vsize += strlen (o_options[i].name) + 1;
tflag[i] = 1;
}
}
else if (GET_BINARY_O_OPTION_VALUE (i, o_options[i].name))
{
vsize += strlen (o_options[i].name) + 1;
tflag[i] = 1;
}
}
value = (char *)xmalloc (vsize + 1);
for (i = vptr = 0; o_options[i].name; i++)
{
if (tflag[i])
{
strcpy (value + vptr, o_options[i].name);
vptr += strlen (o_options[i].name);
value[vptr++] = ':';
}
}
if (vptr)
vptr--; /* cut off trailing colon */
value[vptr] = '\0';
v = find_variable ("SHELLOPTS");
/* Turn off the read-only attribute so we can bind the new value, and
note whether or not the variable was exported. */
if (v)
{
VUNSETATTR (v, att_readonly);
exported = exported_p (v);
}
else
exported = 0;
v = bind_variable ("SHELLOPTS", value, 0);
/* Turn the read-only attribute back on, and turn off the export attribute
if it was set implicitly by mark_modified_vars and SHELLOPTS was not
exported before we bound the new value. */
VSETATTR (v, att_readonly);
if (mark_modified_vars && exported == 0 && exported_p (v))
VUNSETATTR (v, att_exported);
free (value);
}
void
parse_shellopts (value)
char *value;
{
char *vname;
int vptr;
vptr = 0;
while (vname = extract_colon_unit (value, &vptr))
{
set_minus_o_option (FLAG_ON, vname);
free (vname);
}
}
void
initialize_shell_options (no_shellopts)
int no_shellopts;
{
char *temp;
SHELL_VAR *var;
if (no_shellopts == 0)
{
var = find_variable ("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));
if (temp)
{
parse_shellopts (temp);
free (temp);
}
}
}
/* Set up the $SHELLOPTS variable. */
set_shellopts ();
}
/* Reset the values of the -o options that are not also shell flags. This is
called from execute_cmd.c:initialize_subshell() when setting up a subshell
to run an executable shell script without a leading `#!'. */
void
reset_shell_options ()
{
#if defined (HISTORY)
remember_on_history = 1;
#endif
ignoreeof = 0;
}
/* Set some flags from the word values in the input list. If LIST is empty,
then print out the values of the variables instead. If LIST contains
non-flags, then set $1 - $9 to the successive words of LIST. */
int
set_builtin (list)
WORD_LIST *list;
{
int on_or_off, flag_name, force_assignment, opts_changed;
WORD_LIST *l;
register char *arg;
char s[3];
if (list == 0)
{
print_all_shell_variables ();
return (EXECUTION_SUCCESS);
}
/* Check validity of flag arguments. */
reset_internal_getopt ();
while ((flag_name = internal_getopt (list, optflags)) != -1)
{
switch (flag_name)
{
case '?':
builtin_usage ();
return (list_optopt == '?' ? EXECUTION_SUCCESS : EX_USAGE);
default:
break;
}
}
/* Do the set command. While the list consists of words starting with
'-' or '+' treat them as flags, otherwise, start assigning them to
$1 ... $n. */
for (force_assignment = opts_changed = 0; list; )
{
arg = list->word->word;
/* If the argument is `--' or `-' then signal the end of the list
and remember the remaining arguments. */
if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
{
list = list->next;
/* `set --' unsets the positional parameters. */
if (arg[1] == '-')
force_assignment = 1;
/* Until told differently, the old shell behaviour of
`set - [arg ...]' being equivalent to `set +xv [arg ...]'
stands. Posix.2 says the behaviour is marked as obsolescent. */
else
{
change_flag ('x', '+');
change_flag ('v', '+');
opts_changed = 1;
}
break;
}
if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+'))
{
while (flag_name = *++arg)
{
if (flag_name == '?')
{
builtin_usage ();
return (EXECUTION_SUCCESS);
}
else if (flag_name == 'o') /* -+o option-name */
{
char *option_name;
WORD_LIST *opt;
opt = list->next;
if (opt == 0)
{
list_minus_o_opts (-1, (on_or_off == '+'));
continue;
}
option_name = opt->word->word;
if (option_name == 0 || *option_name == '\0' ||
*option_name == '-' || *option_name == '+')
{
list_minus_o_opts (-1, (on_or_off == '+'));
continue;
}
list = list->next; /* Skip over option name. */
opts_changed = 1;
if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS)
{
set_shellopts ();
return (EXECUTION_FAILURE);
}
}
else if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
{
s[0] = on_or_off;
s[1] = flag_name;
s[2] = '\0';
sh_invalidopt (s);
builtin_usage ();
set_shellopts ();
return (EXECUTION_FAILURE);
}
opts_changed = 1;
}
}
else
{
break;
}
list = list->next;
}
/* Assigning $1 ... $n */
if (list || force_assignment)
remember_args (list, 1);
/* Set up new value of $SHELLOPTS */
if (opts_changed)
set_shellopts ();
return (EXECUTION_SUCCESS);
}
$BUILTIN unset
$FUNCTION unset_builtin
$SHORT_DOC unset [-f] [-v] [name ...]
For each NAME, remove the corresponding variable or function. Given
the `-v', unset will only act on variables. Given the `-f' flag,
unset will only act on functions. With neither flag, unset first
tries to unset a variable, and if that fails, then tries to unset a
function. Some variables cannot be unset; also see readonly.
$END
#define NEXT_VARIABLE() any_failed++; list = list->next; continue;
int
unset_builtin (list)
WORD_LIST *list;
{
int unset_function, unset_variable, unset_array, opt, any_failed;
char *name;
unset_function = unset_variable = unset_array = any_failed = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "fv")) != -1)
{
switch (opt)
{
case 'f':
unset_function = 1;
break;
case 'v':
unset_variable = 1;
break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (unset_function && unset_variable)
{
builtin_error (_("cannot simultaneously unset a function and a variable"));
return (EXECUTION_FAILURE);
}
while (list)
{
SHELL_VAR *var;
int tem;
#if defined (ARRAY_VARS)
char *t;
#endif
name = list->word->word;
#if defined (ARRAY_VARS)
unset_array = 0;
if (!unset_function && valid_array_reference (name))
{
t = strchr (name, '[');
*t++ = '\0';
unset_array++;
}
#endif
/* Bash allows functions with names which are not valid identifiers
to be created when not in posix mode, so check only when in posix
mode when unsetting a function. */
if (((unset_function && posixly_correct) || !unset_function) && legal_identifier (name) == 0)
{
sh_invalidid (name);
NEXT_VARIABLE ();
}
var = unset_function ? find_function (name) : find_variable (name);
if (var && !unset_function && non_unsettable_p (var))
{
builtin_error (_("%s: cannot unset"), name);
NEXT_VARIABLE ();
}
/* Posix.2 says that unsetting readonly variables is an error. */
if (var && readonly_p (var))
{
builtin_error (_("%s: cannot unset: readonly %s"),
name, unset_function ? "function" : "variable");
NEXT_VARIABLE ();
}
/* Unless the -f option is supplied, the name refers to a variable. */
#if defined (ARRAY_VARS)
if (var && unset_array)
{
if (array_p (var) == 0)
{
builtin_error (_("%s: not an array variable"), name);
NEXT_VARIABLE ();
}
else
{
tem = unbind_array_element (var, t);
if (tem == -1)
any_failed++;
}
}
else
#endif /* ARRAY_VARS */
tem = unset_function ? unbind_func (name) : unbind_variable (name);
/* This is what Posix.2 draft 11+ says. ``If neither -f nor -v
is specified, the name refers to a variable; if a variable by
that name does not exist, a function by that name, if any,
shall be unset.'' */
if (tem == -1 && !unset_function && !unset_variable)
tem = unbind_func (name);
/* SUSv3, POSIX.1-2001 say: ``Unsetting a variable or function that
was not previously set shall not be considered an error.'' */
if (unset_function == 0)
stupidly_hack_special_variables (name);
list = list->next;
}
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
}
+17 -4
View File
@@ -1,7 +1,7 @@
This file is setattr.def, from which is created setattr.c.
It implements the builtins "export" and "readonly", in Bash.
Copyright (C) 1987-2003 Free Software Foundation, Inc.
Copyright (C) 1987-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -111,6 +111,7 @@ set_or_show_attributes (list, attribute, nodefs)
{
register SHELL_VAR *var;
int assign, undo, functions_only, arrays_only, any_failed, assign_error, opt;
int aflags;
char *name;
#if defined (ARRAY_VARS)
WORD_LIST *nlist, *tlist;
@@ -175,8 +176,16 @@ set_or_show_attributes (list, attribute, nodefs)
/* xxx [-np] name[=value] */
assign = assignment (name, 0);
aflags = 0;
if (assign)
name[assign] = '\0';
{
name[assign] = '\0';
if (name[assign - 1] == '+')
{
aflags |= ASS_APPEND;
name[assign - 1] = '\0';
}
}
if (legal_identifier (name) == 0)
{
@@ -192,6 +201,8 @@ set_or_show_attributes (list, attribute, nodefs)
if (assign) /* xxx [-np] name=value */
{
name[assign] = '=';
if (aflags & ASS_APPEND)
name[assign - 1] = '+';
#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. */
@@ -217,6 +228,8 @@ set_or_show_attributes (list, attribute, nodefs)
if (do_assignment_no_expand (name) == 0)
assign_error++;
name[assign] = '\0';
if (aflags & ASS_APPEND)
name[assign - 1] = '\0';
}
set_var_attribute (name, attribute, undo);
@@ -396,7 +409,7 @@ set_var_attribute (name, attribute, undo)
{
tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring ("");
var = bind_variable (tv->name, tvalue);
var = bind_variable (tv->name, tvalue, 0);
var->attributes |= tv->attributes & ~att_tempvar;
VSETATTR (tv, att_propagate);
if (var->context != 0)
@@ -410,7 +423,7 @@ set_var_attribute (name, attribute, undo)
var = find_variable_internal (name, 0);
if (var == 0)
{
var = bind_variable (name, (char *)NULL);
var = bind_variable (name, (char *)NULL, 0);
VSETATTR (var, att_invisible);
}
else if (var->context != 0)
+439
View File
@@ -0,0 +1,439 @@
This file is setattr.def, from which is created setattr.c.
It implements the builtins "export" and "readonly", in Bash.
Copyright (C) 1987-2003 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.
$PRODUCES setattr.c
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "common.h"
#include "bashgetopt.h"
extern int posixly_correct;
extern int array_needs_making;
extern char *this_command_name;
extern sh_builtin_func_t *this_shell_builtin;
#ifdef ARRAY_VARS
extern int declare_builtin __P((WORD_LIST *));
#endif
#define READONLY_OR_EXPORT \
(this_shell_builtin == readonly_builtin || this_shell_builtin == export_builtin)
$BUILTIN export
$FUNCTION export_builtin
$SHORT_DOC export [-nf] [name[=value] ...] or export -p
NAMEs are marked for automatic export to the environment of
subsequently executed commands. If the -f option is given,
the NAMEs refer to functions. If no NAMEs are given, or if `-p'
is given, a list of all names that are exported in this shell is
printed. An argument of `-n' says to remove the export property
from subsequent NAMEs. An argument of `--' disables further option
processing.
$END
/* For each variable name in LIST, make that variable appear in the
environment passed to simple commands. If there is no LIST, then
print all such variables. An argument of `-n' says to remove the
exported attribute from variables named in LIST. An argument of
-f indicates that the names present in LIST refer to functions. */
int
export_builtin (list)
register WORD_LIST *list;
{
return (set_or_show_attributes (list, att_exported, 0));
}
$BUILTIN readonly
$FUNCTION readonly_builtin
$SHORT_DOC readonly [-af] [name[=value] ...] or readonly -p
The given NAMEs are marked readonly and the values of these NAMEs may
not be changed by subsequent assignment. If the -f option is given,
then functions corresponding to the NAMEs are so marked. If no
arguments are given, or if `-p' is given, a list of all readonly names
is printed. The `-a' option means to treat each NAME as
an array variable. An argument of `--' disables further option
processing.
$END
/* For each variable name in LIST, make that variable readonly. Given an
empty LIST, print out all existing readonly variables. */
int
readonly_builtin (list)
register WORD_LIST *list;
{
return (set_or_show_attributes (list, att_readonly, 0));
}
#if defined (ARRAY_VARS)
# define ATTROPTS "afnp"
#else
# define ATTROPTS "fnp"
#endif
/* For each variable name in LIST, make that variable have the specified
ATTRIBUTE. An arg of `-n' says to remove the attribute from the the
remaining names in LIST (doesn't work for readonly). */
int
set_or_show_attributes (list, attribute, nodefs)
register WORD_LIST *list;
int attribute, nodefs;
{
register SHELL_VAR *var;
int assign, undo, functions_only, arrays_only, any_failed, assign_error, opt;
int aflags;
char *name;
#if defined (ARRAY_VARS)
WORD_LIST *nlist, *tlist;
WORD_DESC *w;
#endif
undo = functions_only = arrays_only = any_failed = assign_error = 0;
/* Read arguments from the front of the list. */
reset_internal_getopt ();
while ((opt = internal_getopt (list, ATTROPTS)) != -1)
{
switch (opt)
{
case 'n':
undo = 1;
break;
case 'f':
functions_only = 1;
break;
#if defined (ARRAY_VARS)
case 'a':
arrays_only = 1;
break;
#endif
case 'p':
break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (list)
{
if (attribute & att_exported)
array_needs_making = 1;
/* Cannot undo readonly status, silently disallowed. */
if (undo && (attribute & att_readonly))
attribute &= ~att_readonly;
while (list)
{
name = list->word->word;
if (functions_only) /* xxx -f name */
{
var = find_function (name);
if (var == 0)
{
builtin_error (_("%s: not a function"), name);
any_failed++;
}
else
SETVARATTR (var, attribute, undo);
list = list->next;
continue;
}
/* xxx [-np] name[=value] */
assign = assignment (name, 0);
aflags = 0;
if (assign)
{
name[assign] = '\0';
if (name[assign - 1] == '+')
{
aflags |= ASS_APPEND;
name[assign - 1] = '\0';
}
}
if (legal_identifier (name) == 0)
{
sh_invalidid (name);
if (assign)
assign_error++;
else
any_failed++;
list = list->next;
continue;
}
if (assign) /* xxx [-np] name=value */
{
name[assign] = '=';
if (aflags & ASS_APPEND)
name[assign - 1] = '+';
#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)
{
tlist = list->next;
list->next = (WORD_LIST *)NULL;
w = make_word ("-ra");
nlist = make_word_list (w, list);
opt = declare_builtin (nlist);
if (opt != EXECUTION_SUCCESS)
assign_error++;
list->next = tlist;
dispose_word (w);
free (nlist);
}
else
#endif
/* This word has already been expanded once with command
and parameter expansion. Call do_assignment_no_expand (),
which does not do command or parameter substitution. If
the assignment is not performed correctly, flag an error. */
if (do_assignment_no_expand (name) == 0)
assign_error++;
name[assign] = '\0';
if (aflags & ASS_APPEND)
name[assign - 1] = '\0';
}
set_var_attribute (name, attribute, undo);
list = list->next;
}
}
else
{
SHELL_VAR **variable_list;
register int i;
if ((attribute & att_function) || functions_only)
{
variable_list = all_shell_functions ();
if (attribute != att_function)
attribute &= ~att_function; /* so declare -xf works, for example */
}
else
variable_list = all_shell_variables ();
#if defined (ARRAY_VARS)
if (attribute & att_array)
{
arrays_only++;
if (attribute != att_array)
attribute &= ~att_array;
}
#endif
if (variable_list)
{
for (i = 0; var = variable_list[i]; i++)
{
#if defined (ARRAY_VARS)
if (arrays_only && array_p (var) == 0)
continue;
#endif
if ((var->attributes & attribute))
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
}
free (variable_list);
}
}
return (assign_error ? EX_BADASSIGN
: ((any_failed == 0) ? EXECUTION_SUCCESS
: EXECUTION_FAILURE));
}
/* Show the attributes for shell variable VAR. If NODEFS is non-zero,
don't show function definitions along with the name. If PATTR is
non-zero, it indicates we're being called from `export' or `readonly'.
In POSIX mode, this prints the name of the calling builtin (`export'
or `readonly') instead of `declare', and doesn't print function defs
when called by `export' or `readonly'. */
int
show_var_attributes (var, pattr, nodefs)
SHELL_VAR *var;
int pattr, nodefs;
{
char flags[8], *x;
int i;
i = 0;
/* pattr == 0 means we are called from `declare'. */
if (pattr == 0 || posixly_correct == 0)
{
#if defined (ARRAY_VARS)
if (array_p (var))
flags[i++] = 'a';
#endif
if (function_p (var))
flags[i++] = 'f';
if (integer_p (var))
flags[i++] = 'i';
if (readonly_p (var))
flags[i++] = 'r';
if (trace_p (var))
flags[i++] = 't';
if (exported_p (var))
flags[i++] = 'x';
}
else
{
#if defined (ARRAY_VARS)
if (array_p (var))
flags[i++] = 'a';
#endif
if (function_p (var))
flags[i++] = 'f';
}
flags[i] = '\0';
/* If we're printing functions with definitions, print the function def
first, then the attributes, instead of printing output that can't be
reused as input to recreate the current state. */
if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0))
{
printf ("%s\n", named_function_string (var->name, function_cell (var), 1));
nodefs++;
if (pattr == 0 && i == 1 && flags[0] == 'f')
return 0; /* don't print `declare -f name' */
}
if (pattr == 0 || posixly_correct == 0)
printf ("declare -%s ", i ? flags : "-");
else if (i)
printf ("%s -%s ", this_command_name, flags);
else
printf ("%s ", this_command_name);
#if defined (ARRAY_VARS)
if (array_p (var))
print_array_assignment (var, 1);
else
#endif
/* force `readonly' and `export' to not print out function definitions
when in POSIX mode. */
if (nodefs || (function_p (var) && pattr != 0 && posixly_correct))
printf ("%s\n", var->name);
else if (function_p (var))
printf ("%s\n", named_function_string (var->name, function_cell (var), 1));
else if (invisible_p (var))
printf ("%s\n", var->name);
else
{
x = sh_double_quote (var_isset (var) ? value_cell (var) : "");
printf ("%s=%s\n", var->name, x);
free (x);
}
return (0);
}
int
show_name_attributes (name, nodefs)
char *name;
int nodefs;
{
SHELL_VAR *var;
var = find_variable_internal (name, 1);
if (var && invisible_p (var) == 0)
{
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
return (0);
}
else
return (1);
}
void
set_var_attribute (name, attribute, undo)
char *name;
int attribute, undo;
{
SHELL_VAR *var, *tv;
char *tvalue;
if (undo)
var = find_variable (name);
else
{
tv = find_tempenv_variable (name);
/* XXX -- need to handle case where tv is a temp variable in a
function-scope context, since function_env has been merged into
the local variables table. */
if (tv && tempvar_p (tv))
{
tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring ("");
var = bind_variable (tv->name, tvalue, 0);
var->attributes |= tv->attributes & ~att_tempvar;
VSETATTR (tv, att_propagate);
if (var->context != 0)
VSETATTR (var, att_propagate);
SETVARATTR (tv, attribute, undo); /* XXX */
free (tvalue);
}
else
{
var = find_variable_internal (name, 0);
if (var == 0)
{
var = bind_variable (name, (char *)NULL, 0);
VSETATTR (var, att_invisible);
}
else if (var->context != 0)
VSETATTR (var, att_propagate);
}
}
if (var)
SETVARATTR (var, attribute, undo);
if (var && (exported_p (var) || (attribute & att_exported)))
array_needs_making++; /* XXX */
}
+16 -2
View File
@@ -6,12 +6,12 @@
.\" Case Western Reserve University
.\" chet@po.CWRU.Edu
.\"
.\" Last Change: Sat Oct 30 22:24:07 EDT 2004
.\" Last Change: Sun Nov 7 14:53:18 EST 2004
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
.TH BASH 1 "2004 Oct 30" "GNU Bash-3.1-devel"
.TH BASH 1 "2004 Nov 7" "GNU Bash-3.1-devel"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
@@ -1076,6 +1076,20 @@ Assignment statements may also appear as arguments to the
and
.B local
builtin commands.
.PP
In the context where an assignment statement is assigning a value
to a shell variable or array index, the += operator can be used to
append to or add to the variable's previous value.
When += is applied to a variable for which the integer attribute has been
set, \fIvalue\fP is evaluated as an arithmetic expression and added to the
variable's current value, which is also evaluated.
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.
When applied to a string-valued variable, \fIvalue\fP is expanded and
appended to the variable's value.
.SS Positional Parameters
.PP
A
+5 -5
View File
@@ -6,12 +6,12 @@
.\" Case Western Reserve University
.\" chet@po.CWRU.Edu
.\"
.\" Last Change: Sat Oct 2 18:05:57 EDT 2004
.\" Last Change: Sat Oct 30 22:24:07 EDT 2004
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
.TH BASH 1 "2004 Oct 2" "GNU Bash-3.1-devel"
.TH BASH 1 "2004 Oct 30" "GNU Bash-3.1-devel"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
@@ -8541,9 +8541,9 @@ subsequently reset. The exit status is true unless a
.I name
is readonly.
.TP
\fBwait\fP [\fIn\fP]
Wait for the specified process and return its termination
status.
\fBwait\fP [\fIn ...\fP]
Wait for each specified process and return its termination status.
Each
.I n
may be a process
ID or a job specification; if a job spec is given, all processes
+15
View File
@@ -1208,6 +1208,21 @@ Assignment statements may also appear as arguments to the
@code{declare}, @code{typeset}, @code{export}, @code{readonly},
and @code{local} builtin commands.
In the context where an assignment statement is assigning a value
to a shell variable or array index (@pxref{Arrays}), the @samp{+=}
operator can be used to
append to or add to the variable's previous value.
When @samp{+=} is applied to a variable for which the integer attribute
has been set, @var{value} is evaluated as an arithmetic expression and
added to the variable's current value, which is also evaluated.
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.
When applied to a string-valued variable, @var{value} is expanded and
appended to the variable's value.
@node Positional Parameters
@subsection Positional Parameters
@cindex parameters, positional
+4 -4
View File
@@ -6252,11 +6252,11 @@ or non-zero if an error occurs or an invalid option is encountered.
@item wait
@btindex wait
@example
wait [@var{jobspec} or @var{pid}]
wait [@var{jobspec} or @var{pid} ...]
@end example
Wait until the child process specified by process @sc{id} @var{pid} or job
specification @var{jobspec} exits and return the exit status of the last
command waited for.
Wait until the child process specified by each process @sc{id} @var{pid}
or job specification @var{jobspec} exits and return the exit status of the
last command waited for.
If a job spec is given, all processes in the job are waited for.
If no arguments are given, all currently active child processes are
waited for, and the return status is zero.
+3 -3
View File
@@ -4,7 +4,7 @@ Copyright (C) 1988-2004 Free Software Foundation, Inc.
@set EDITION 3.1-devel
@set VERSION 3.1-devel
@set UPDATED 30 October 2004
@set UPDATED-MONTH October 2004
@set UPDATED 7 November 2004
@set UPDATED-MONTH November 2004
@set LASTCHANGE Sat Oct 30 22:24:26 EDT 2004
@set LASTCHANGE Sun Nov 7 15:09:53 EST 2004
+3 -3
View File
@@ -4,7 +4,7 @@ Copyright (C) 1988-2004 Free Software Foundation, Inc.
@set EDITION 3.1-devel
@set VERSION 3.1-devel
@set UPDATED 20 October 2004
@set UPDATED-MONTH October 2004
@set UPDATED 7 November 2004
@set UPDATED-MONTH November 2004
@set LASTCHANGE Wed Oct 20 09:54:44 EDT 2004
@set LASTCHANGE
+5 -5
View File
@@ -1,6 +1,6 @@
/* execute_command.c -- Execute a COMMAND structure. */
/* Copyright (C) 1987-2003 Free Software Foundation, Inc.
/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -1635,7 +1635,7 @@ execute_for_command (for_command)
#endif
this_command_name = (char *)NULL;
v = bind_variable (identifier, list->word->word);
v = bind_variable (identifier, list->word->word, 0);
if (readonly_p (v) || noassign_p (v))
{
line_number = save_line_number;
@@ -1682,7 +1682,7 @@ execute_for_command (for_command)
{
SHELL_VAR *new_value;
new_value = bind_variable (identifier, value_cell(old_value));
new_value = bind_variable (identifier, value_cell(old_value), 0);
new_value->attributes = old_value->attributes;
dispose_variable (old_value);
}
@@ -2089,7 +2089,7 @@ execute_select_command (select_command)
break;
}
v = bind_variable (identifier, selection);
v = bind_variable (identifier, selection, 0);
if (readonly_p (v) || noassign_p (v))
{
if (readonly_p (v) && interactive_shell == 0 && posixly_correct)
@@ -2566,7 +2566,7 @@ bind_lastarg (arg)
if (arg == 0)
arg = "";
var = bind_variable ("_", arg);
var = bind_variable ("_", arg, 0);
VUNSETATTR (var, att_exported);
}
-2
View File
@@ -2281,7 +2281,6 @@ execute_while_or_until (while_command, type)
return_value = execute_command (while_command->test);
REAP ();
itrace("execute_while_or_until: test returns %d", return_value);
/* Need to handle `break' in the test when we would break out of the
loop. The job control code will set `breaking' to loop_level
when a job in a loop is stopped with SIGTSTP. If the stopped job
@@ -2304,7 +2303,6 @@ itrace("execute_while_or_until: test returns %d", return_value);
body_status = execute_command (while_command->action);
QUIT;
itrace("execute_while_or_until: body returns %d", body_status);
if (breaking)
{
breaking--;
+6
View File
@@ -288,10 +288,16 @@ assignment (string, flags)
newi = skipsubscript (string, indx);
if (string[newi++] != ']')
return (0);
if (string[newi] == '+' && string[newi+1] == '=')
return (newi + 1);
return ((string[newi] == '=') ? newi : 0);
}
#endif /* ARRAY_VARS */
/* Check for `+=' */
if (c == '+' && string[indx+1] == '=')
return (indx + 1);
/* Variable names in assignment statements may contain only letters,
digits, and `_'. */
if (legal_variable_char (c) == 0)
+11 -1
View File
@@ -269,7 +269,7 @@ assignment (string, flags)
c = string[indx = 0];
#if defined (ARRAY_VARS)
if ((legal_variable_starter (c) == 0) && (flags && c != '[')) /* ] */
if ((legal_variable_starter (c) == 0) && (flags == 0 || c != '[')) /* ] */
#else
if (legal_variable_starter (c) == 0)
#endif
@@ -288,10 +288,16 @@ assignment (string, flags)
newi = skipsubscript (string, indx);
if (string[newi++] != ']')
return (0);
if (string[newi] == '+' && string[newi+1] == '=')
return (flags ? 0 : (newi + 1));
return ((string[newi] == '=') ? newi : 0);
}
#endif /* ARRAY_VARS */
/* Check for `+=' */
if (c == '+' && string[indx+1] == '=')
return (indx + 1);
/* Variable names in assignment statements may contain only letters,
digits, and `_'. */
if (legal_variable_char (c) == 0)
@@ -802,6 +808,10 @@ bash_tilde_find_word (s, flags, lenp)
for (r = s; *r && *r != '/'; r++)
{
/* Short-circuit immediately if we see a quote character. Even though
POSIX says that `the first unquoted slash' (or `:') terminates the
tilde-prefix, in practice, any quoted portion of the tilde prefix
will cause it to not be expanded. */
if (*r == '\\' || *r == '\'' || *r == '"')
{
ret = savestring (s);
+5 -2
View File
@@ -964,8 +964,11 @@ rl_redisplay ()
tx = _rl_col_width (&visible_line[pos], 0, nleft);
else
tx = nleft;
_rl_backspace (_rl_last_c_pos - tx); /* XXX */
_rl_last_c_pos = tx;
if (_rl_last_c_pos != tx)
{
_rl_backspace (_rl_last_c_pos - tx); /* XXX */
_rl_last_c_pos = tx;
}
}
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+3 -3
View File
@@ -1,6 +1,6 @@
/* mailcheck.c -- The check is in the mail... */
/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -385,7 +385,7 @@ check_mail ()
use_user_notification = mailfiles[i]->msg != (char *)NULL;
message = mailfiles[i]->msg ? mailfiles[i]->msg : _("You have mail in $_");
bind_variable ("_", current_mail_file);
bind_variable ("_", current_mail_file, 0);
#define atime mailfiles[i]->access_time
#define mtime mailfiles[i]->mod_time
@@ -430,7 +430,7 @@ check_mail ()
if (dollar_underscore)
{
bind_variable ("_", dollar_underscore);
bind_variable ("_", dollar_underscore, 0);
free (dollar_underscore);
}
else
+1 -3
View File
@@ -184,9 +184,7 @@ reset_mail_files ()
register int i;
for (i = 0; i < mailfiles_count; i++)
{
RESET_MAIL_FILE (i);
}
RESET_MAIL_FILE (i);
}
/* Free the information that we have about the remembered mail files. */
+2 -1
View File
@@ -2145,7 +2145,7 @@ execute_prompt_command (command)
parse_and_execute (savestring (command), "PROMPT_COMMAND", SEVAL_NONINT|SEVAL_NOHIST);
restore_parser_state (&ps);
bind_variable ("_", last_lastarg);
bind_variable ("_", last_lastarg, 0);
FREE (last_lastarg);
if (token_to_read == '\n') /* reset_parser was called */
@@ -3252,6 +3252,7 @@ token_is_assignment (t, i)
return r;
}
/* XXX - possible changes here for `+=' */
static int
token_is_ident (t, i)
char *t;
+39 -27
View File
@@ -962,22 +962,26 @@ pipeline_command: pipeline
{ $$ = $1; }
| BANG pipeline
{
$2->flags |= CMD_INVERT_RETURN;
if ($2)
$2->flags |= CMD_INVERT_RETURN;
$$ = $2;
}
| timespec pipeline
{
$2->flags |= $1;
if ($2)
$2->flags |= $1;
$$ = $2;
}
| timespec BANG pipeline
{
$3->flags |= $1|CMD_INVERT_RETURN;
if ($3)
$3->flags |= $1|CMD_INVERT_RETURN;
$$ = $3;
}
| BANG timespec pipeline
{
$3->flags |= $2|CMD_INVERT_RETURN;
if ($3)
$3->flags |= $2|CMD_INVERT_RETURN;
$$ = $3;
}
| timespec list_terminator
@@ -2141,7 +2145,7 @@ execute_prompt_command (command)
parse_and_execute (savestring (command), "PROMPT_COMMAND", SEVAL_NONINT|SEVAL_NOHIST);
restore_parser_state (&ps);
bind_variable ("_", last_lastarg);
bind_variable ("_", last_lastarg, 0);
FREE (last_lastarg);
if (token_to_read == '\n') /* reset_parser was called */
@@ -2726,7 +2730,11 @@ parse_matched_pair (qc, open, close, lenp, flags)
start_lineno = line_number;
while (count)
{
#if 0
ch = shell_getc ((qc != '\'' || (flags & P_ALLOWESC)) && pass_next_character == 0);
#else
ch = shell_getc (qc != '\'' && pass_next_character == 0);
#endif
if (ch == EOF)
{
free (ret);
@@ -2806,6 +2814,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
/* Translate $'...' here. */
ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen);
xfree (nestret);
nestret = sh_single_quote (ttrans);
free (ttrans);
nestlen = strlen (nestret);
@@ -2816,13 +2825,10 @@ parse_matched_pair (qc, open, close, lenp, flags)
/* Locale expand $"..." here. */
ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen);
xfree (nestret);
nestret = (char *)xmalloc (ttranslen + 3);
nestret[0] = '"';
strcpy (nestret + 1, ttrans);
nestret[ttranslen + 1] = '"';
nestret[ttranslen += 2] = '\0';
nestret = sh_mkdoublequoted (ttrans, ttranslen, 0);
free (ttrans);
nestlen = ttranslen;
nestlen = ttranslen + 2;
retind -= 2; /* back up before the $" */
}
@@ -2921,19 +2927,12 @@ parse_dparen (c)
if (reserved_word_acceptable (last_read_token))
{
sline = line_number;
#if 0
cmdtyp = parse_arith_cmd (&wval, 1);
#else
cmdtyp = parse_arith_cmd (&wval, 0);
#endif
if (cmdtyp == 1) /* arithmetic command */
{
wd = make_word (wval);
#if 0
wd->flags = W_QUOTED;
#else
wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB;
#endif
yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL);
free (wval); /* make_word copies it */
return (ARITH_CMD);
@@ -3253,6 +3252,7 @@ token_is_assignment (t, i)
return r;
}
/* XXX - possible changes here for `+=' */
static int
token_is_ident (t, i)
char *t;
@@ -3285,6 +3285,10 @@ read_token_word (character)
/* DOLLAR_PRESENT becomes non-zero if we see a `$'. */
int dollar_present;
/* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound
assignment. */
int compound_assignment;
/* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */
int quoted;
@@ -3304,7 +3308,7 @@ read_token_word (character)
token_index = 0;
all_digit_token = DIGIT (character);
dollar_present = quoted = pass_next_character = 0;
dollar_present = quoted = pass_next_character = compound_assignment = 0;
for (;;)
{
@@ -3449,27 +3453,25 @@ read_token_word (character)
{
ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen);
free (ttok);
/* Insert the single quotes and correctly quote any
embedded single quotes (allowed because P_ALLOWESC was
passed to parse_matched_pair). */
ttok = sh_single_quote (ttrans);
free (ttrans);
ttranslen = strlen (ttok);
ttrans = ttok;
ttranslen = strlen (ttrans);
}
else
{
/* Try to locale-expand the converted string. */
/* Try to locale)-expand the converted string. */
ttrans = localeexpand (ttok, 0, ttoklen - 1, first_line, &ttranslen);
free (ttok);
/* Add the double quotes back */
ttok = (char *)xmalloc (ttranslen + 3);
ttok[0] = '"';
strcpy (ttok + 1, ttrans);
ttok[ttranslen + 1] = '"';
ttok[ttranslen += 2] = '\0';
ttok = sh_mkdoublequoted (ttrans, ttranslen, 0);
free (ttrans);
ttranslen += 2;
ttrans = ttok;
}
@@ -3522,6 +3524,7 @@ read_token_word (character)
goto next_character;
}
/* Identify possible compound array variable assignment. */
/* XXX - changes here for `+=' */
else if MBTEST(character == '=' && token_index > 0 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && token_is_assignment (token, token_index))
{
peek_char = shell_getc (1);
@@ -3543,7 +3546,12 @@ read_token_word (character)
token[token_index++] = ')';
FREE (ttok);
all_digit_token = 0;
compound_assignment = 1;
#if 0
goto next_character;
#else
goto got_token; /* ksh93 seems to do this */
#endif
}
else
shell_ungetc (peek_char);
@@ -3638,6 +3646,8 @@ got_token:
the_word->flags |= W_HASDOLLAR;
if (quoted)
the_word->flags |= W_QUOTED;
if (compound_assignment)
the_word->flags |= W_COMPASSIGN;
/* A word is an assignment if it appears at the beginning of a
simple command, or after another assignment word. This is
context-dependent, so it cannot be handled in the grammar. */
@@ -3814,6 +3824,8 @@ history_delimiting_chars ()
return " ";
return ";";
}
else if (two_tokens_ago == CASE && token_before_that == WORD && (parser_state & PST_CASESTMT))
return " ";
for (i = 0; no_semi_successors[i]; i++)
{
+2 -2
View File
@@ -862,7 +862,7 @@ bind_comp_words (lwords)
VUNSETATTR (v, att_readonly);
if (array_p (v) == 0)
v = convert_var_to_array (v);
v = assign_array_var_from_word_list (v, lwords);
v = assign_array_var_from_word_list (v, lwords, 0);
VUNSETATTR (v, att_invisible);
return v;
@@ -882,7 +882,7 @@ bind_compfunc_variables (line, ind, lwords, cw, exported)
/* Set the variables that the function expects while it executes. Maybe
these should be in the function environment (temporary_env). */
v = bind_variable ("COMP_LINE", line);
v = bind_variable ("COMP_LINE", line, 0);
if (v && exported)
VSETATTR(v, att_exported);
+5 -1
View File
@@ -862,7 +862,9 @@ bind_comp_words (lwords)
VUNSETATTR (v, att_readonly);
if (array_p (v) == 0)
v = convert_var_to_array (v);
v = assign_array_var_from_word_list (v, lwords);
v = assign_array_var_from_word_list (v, lwords, 0);
VUNSETATTR (v, att_invisible);
return v;
}
#endif /* ARRAY_VARS */
@@ -1022,6 +1024,8 @@ gen_shell_function_matches (cs, text, line, ind, lwords, nw, cw)
if (array_p (v) == 0)
v = convert_var_to_array (v);
VUNSETATTR (v, att_invisible);
a = array_cell (v);
if (a == 0 || array_empty (a))
sl = (STRINGLIST *)NULL;
+2 -2
View File
@@ -511,7 +511,7 @@ main (argc, argv, env)
alias expansion in non-interactive shells, and other Posix.2 things. */
if (posixly_correct)
{
bind_variable ("POSIXLY_CORRECT", "y");
bind_variable ("POSIXLY_CORRECT", "y", 0);
sv_strict_posix ("POSIXLY_CORRECT");
}
@@ -610,7 +610,7 @@ main (argc, argv, env)
/* If we are invoked as `sh', turn on Posix mode. */
if (act_like_sh)
{
bind_variable ("POSIXLY_CORRECT", "y");
bind_variable ("POSIXLY_CORRECT", "y", 0);
sv_strict_posix ("POSIXLY_CORRECT");
}
+2
View File
@@ -1089,6 +1089,8 @@ shell_is_restricted (name)
if (restricted)
return 1;
temp = base_pathname (name);
if (*temp == '-')
temp++;
return (STREQ (temp, RESTRICTED_SHELL_NAME));
}
+36 -15
View File
@@ -2143,22 +2143,24 @@ list_string_with_quotes (string)
#if defined (ARRAY_VARS)
static SHELL_VAR *
do_compound_assignment (name, value, mklocal)
do_compound_assignment (name, value, flags)
char *name, *value;
int mklocal;
int flags;
{
SHELL_VAR *v;
int off;
int off, mklocal;
mklocal = flags & ASS_MKLOCAL;
if (mklocal && variable_context)
{
v = find_variable (name);
if (v == 0 || array_p (v) == 0)
v = make_local_array_variable (name);
v = assign_array_var_from_string (v, value);
v = assign_array_var_from_string (v, value, flags);
}
else
v = assign_array_from_string (name, value);
v = assign_array_from_string (name, value, flags);
return (v);
}
@@ -2174,19 +2176,19 @@ do_assignment_internal (word, expand)
const WORD_DESC *word;
int expand;
{
int offset, tlen;
char *name, *value;
int offset, tlen, appendop, assign_list, aflags;
char *name, *value, *ovalue, *nvalue;
SHELL_VAR *entry;
#if defined (ARRAY_VARS)
char *t;
int ni;
#endif
int assign_list = 0;
const char *string;
if (word == 0 || word->word == 0)
return 0;
appendop = assign_list = aflags = 0;
string = word->word;
offset = assignment (string, 0);
name = savestring (string);
@@ -2196,7 +2198,13 @@ do_assignment_internal (word, expand)
{
char *temp;
name[offset] = 0;
if (name[offset - 1] == '+')
{
appendop = 1;
name[offset - 1] = '\0';
}
name[offset] = 0; /* might need this set later */
temp = name + offset + 1;
tlen = STRLEN (temp);
@@ -2226,10 +2234,19 @@ do_assignment_internal (word, expand)
}
if (echo_command_at_execute)
xtrace_print_assignment (name, value, assign_list, 1);
{
if (appendop)
name[offset - 1] = '+';
xtrace_print_assignment (name, value, assign_list, 1);
if (appendop)
name[offset - 1] = '\0';
}
#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0)
if (appendop)
aflags |= ASS_APPEND;
#if defined (ARRAY_VARS)
if (t = xstrchr (name, '[')) /*]*/
{
@@ -2238,15 +2255,19 @@ do_assignment_internal (word, expand)
report_error (_("%s: cannot assign list to array member"), name);
ASSIGN_RETURN (0);
}
entry = assign_array_element (name, value);
entry = assign_array_element (name, value, aflags);
if (entry == 0)
ASSIGN_RETURN (0);
}
else if (assign_list)
entry = do_compound_assignment (name, value, (word->flags & W_ASSIGNARG));
{
if (word->flags & W_ASSIGNARG)
aflags |= ASS_MKLOCAL;
entry = do_compound_assignment (name, value, aflags);
}
else
#endif /* ARRAY_VARS */
entry = bind_variable (name, value);
entry = bind_variable (name, value, aflags);
stupidly_hack_special_variables (name);
@@ -4854,10 +4875,10 @@ parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat)
free (t);
#if defined (ARRAY_VARS)
if (valid_array_reference (name))
assign_array_element (name, t1);
assign_array_element (name, t1, 0);
else
#endif /* ARRAY_VARS */
bind_variable (name, t1);
bind_variable (name, t1, 0);
free (t1);
return (temp);
}
+38 -15
View File
@@ -2143,22 +2143,24 @@ list_string_with_quotes (string)
#if defined (ARRAY_VARS)
static SHELL_VAR *
do_compound_assignment (name, value, mklocal)
do_compound_assignment (name, value, flags)
char *name, *value;
int mklocal;
int flags;
{
SHELL_VAR *v;
int off;
int off, mklocal;
mklocal = flags & ASS_MKLOCAL;
if (mklocal && variable_context)
{
v = find_variable (name);
if (v == 0 || array_p (v) == 0)
v = make_local_array_variable (name);
v = assign_array_var_from_string (v, value);
v = assign_array_var_from_string (v, value, flags);
}
else
v = assign_array_from_string (name, value);
v = assign_array_from_string (name, value, flags);
return (v);
}
@@ -2174,19 +2176,19 @@ do_assignment_internal (word, expand)
const WORD_DESC *word;
int expand;
{
int offset, tlen;
char *name, *value;
int offset, tlen, appendop, assign_list, aflags;
char *name, *value, *ovalue, *nvalue;
SHELL_VAR *entry;
#if defined (ARRAY_VARS)
char *t;
int ni;
#endif
int assign_list = 0;
const char *string;
if (word == 0 || word->word == 0)
return 0;
appendop = assign_list = aflags = 0;
string = word->word;
offset = assignment (string, 0);
name = savestring (string);
@@ -2196,7 +2198,13 @@ do_assignment_internal (word, expand)
{
char *temp;
name[offset] = 0;
if (name[offset - 1] == '+')
{
appendop = 1;
name[offset - 1] = 0;
}
name[offset] = 0; /* might need this set later */
temp = name + offset + 1;
tlen = STRLEN (temp);
@@ -2226,10 +2234,19 @@ do_assignment_internal (word, expand)
}
if (echo_command_at_execute)
xtrace_print_assignment (name, value, assign_list, 1);
{
if (appendop)
name[offset - 1] = '+';
xtrace_print_assignment (name, value, assign_list, 1);
if (appendop)
name[offset - 1] = '+';
}
#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0)
if (appendop)
aflags |= ASS_APPEND;
#if defined (ARRAY_VARS)
if (t = xstrchr (name, '[')) /*]*/
{
@@ -2238,15 +2255,19 @@ do_assignment_internal (word, expand)
report_error (_("%s: cannot assign list to array member"), name);
ASSIGN_RETURN (0);
}
entry = assign_array_element (name, value);
entry = assign_array_element (name, value, aflags);
if (entry == 0)
ASSIGN_RETURN (0);
}
else if (assign_list)
entry = do_compound_assignment (name, value, (word->flags & W_ASSIGNARG));
{
if (word->flags & W_ASSIGNARG)
aflags |= ASS_MKLOCAL;
entry = do_compound_assignment (name, value, aflags);
}
else
#endif /* ARRAY_VARS */
entry = bind_variable (name, value);
entry = bind_variable (name, value, aflags);
stupidly_hack_special_variables (name);
@@ -4854,10 +4875,10 @@ parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat)
free (t);
#if defined (ARRAY_VARS)
if (valid_array_reference (name))
assign_array_element (name, t1);
assign_array_element (name, t1, 0);
else
#endif /* ARRAY_VARS */
bind_variable (name, t1);
bind_variable (name, t1, 0);
free (t1);
return (temp);
}
@@ -6503,10 +6524,12 @@ add_string:
assignoff = sindex;
if (sindex == assignoff && string[sindex+1] == '~') /* XXX */
word->flags |= W_ITILDE;
#if 0
else if ((word->flags & W_ASSIGNMENT) &&
(posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
string[sindex+1] == '~')
word->flags |= W_ITILDE;
#endif
goto add_character;
case ':':
+9 -5
View File
@@ -1,6 +1,6 @@
/* subst.h -- Names of externally visible functions in subst.c. */
/* Copyright (C) 1993-2002 Free Software Foundation, Inc.
/* Copyright (C) 1993-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -31,14 +31,18 @@
to unconditionally retain the backslash. Q_PATQUOTE means that we're
expanding a pattern ${var%#[#%]pattern} in an expansion surrounded
by double quotes. */
#define Q_DOUBLE_QUOTES 0x1
#define Q_HERE_DOCUMENT 0x2
#define Q_KEEP_BACKSLASH 0x4
#define Q_PATQUOTE 0x8
#define Q_DOUBLE_QUOTES 0x01
#define Q_HERE_DOCUMENT 0x02
#define Q_KEEP_BACKSLASH 0x04
#define Q_PATQUOTE 0x08
#define Q_QUOTED 0x10
#define Q_ADDEDQUOTES 0x20
#define Q_QUOTEDNULL 0x40
/* Flag values controlling how assignment statements are treated. */
#define ASS_APPEND 0x01
#define ASS_MKLOCAL 0x02
/* Remove backslashes which are quoting backquotes from STRING. Modifies
STRING, and returns a pointer to it. */
extern char * de_backslash __P((char *));
+9 -4
View File
@@ -31,14 +31,18 @@
to unconditionally retain the backslash. Q_PATQUOTE means that we're
expanding a pattern ${var%#[#%]pattern} in an expansion surrounded
by double quotes. */
#define Q_DOUBLE_QUOTES 0x1
#define Q_HERE_DOCUMENT 0x2
#define Q_KEEP_BACKSLASH 0x4
#define Q_PATQUOTE 0x8
#define Q_DOUBLE_QUOTES 0x01
#define Q_HERE_DOCUMENT 0x02
#define Q_KEEP_BACKSLASH 0x04
#define Q_PATQUOTE 0x08
#define Q_QUOTED 0x10
#define Q_ADDEDQUOTES 0x20
#define Q_QUOTEDNULL 0x40
/* Flag values controlling how assignment statements are treated. */
#define ASS_APPEND 0x01
#define ASS_MKLOCAL 0x02
/* Remove backslashes which are quoting backquotes from STRING. Modifies
STRING, and returns a pointer to it. */
extern char * de_backslash __P((char *));
@@ -98,6 +102,7 @@ extern char *strip_trailing_ifs_whitespace __P((char *, char *, int));
splitting on the result of expansion. */
extern int do_assignment __P((char *));
extern int do_assignment_no_expand __P((char *));
extern int do_word_assignment __P((WORD_DESC *));
/* Append SOURCE to TARGET at INDEX. SIZE is the current amount
of space allocated to TARGET. SOURCE can be NULL, in which
+1 -1
View File
@@ -1,4 +1,4 @@
BUILD_DIR=/usr/local/build/chet/bash/bash-current
BUILD_DIR=/usr/local/build/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
+9 -4
View File
@@ -132,6 +132,11 @@ value = new1 new2 new3
./array1.sub: line 1: `printf "%s\n" -a a=(a 'b c')'
./array2.sub: line 1: syntax error near unexpected token `('
./array2.sub: line 1: `declare -a ''=(a 'b c')'
9
9
7 8 9
a b c d e f g
for case if then else
@@ -139,10 +144,10 @@ for case if then else
12 14 16 18 20
4414758999202
aaa bbb
./array.tests: line 280: syntax error near unexpected token `<>'
./array.tests: line 280: `metas=( <> < > ! )'
./array.tests: line 281: syntax error near unexpected token `<>'
./array.tests: line 281: `metas=( [1]=<> [2]=< [3]=> [4]=! )'
./array.tests: line 282: syntax error near unexpected token `<>'
./array.tests: line 282: `metas=( <> < > ! )'
./array.tests: line 283: syntax error near unexpected token `<>'
./array.tests: line 283: `metas=( [1]=<> [2]=< [3]=> [4]=! )'
abc 3
case 4
abc case if then else 5
+3
View File
@@ -240,6 +240,8 @@ ${THIS_SH} ./array1.sub
${THIS_SH} ./array2.sub
# some old bugs and ksh93 compatibility tests
${THIS_SH} ./array3.sub
set +u
cd /tmp
@@ -394,3 +396,4 @@ unset x[2]
x[9]='9'
echo ${x[*]: -1}
+9
View File
@@ -0,0 +1,9 @@
a=(0 1 2 3 4 5 6 7 8 9)
echo ${a[@]: -1}
echo ${a[@]:9}
echo ${a[@]:10}
echo ${a[@]:11}
echo ${a[@]:7:3}
+1
View File
@@ -77,3 +77,4 @@ a b a,b a-b a:b a;b a_b
a b a,b a-b a.b a:b a;b a_b
a b a,b a-b a.b a:b a;b a_b
a b a,b a-b a.b a:b a;b a_b
argv[1] = <ef>
+3
View File
@@ -353,6 +353,9 @@ echo a@(.|[^[:alnum:]])b
builtin cd /
rm -rf $TESTDIR
x=abcdef
recho "${x#*(a|b)cd}"
# this is for the benefit of pure coverage, so it writes the pcv file
# in the right place
builtin cd $MYDIR
+10
View File
@@ -20,3 +20,13 @@ ok
'abcd'
\'abcd\'
\'abcd\'
argv[1] = <A\CB>
argv[1] = <A\CB>
argv[1] = <ab$cde>
A\CB
A\CB
A\CB
argv[1] = <hello, $"world">
argv[1] = <hello, \$"world">
argv[1] = <hello, $"world">
argv[1] = <hello, $world>
+22
View File
@@ -77,4 +77,26 @@ printf "\'abcd\'\n"
echo -e "\'abcd\'"
echo -e "\\'abcd\\'"
# and what do we do about unrecognized escape sequences?
shopt -s xpg_echo
recho $'A\CB'
recho "A\CB"
cde=c
recho $'ab$cde'
printf "%b\n" 'A\CB'
printf 'A\CB\n'
echo 'A\CB'
world=chet
recho $'hello, $"world"'
recho $'hello, \$"world"'
recho $'hello, $\"world"'
recho "hello, $"world""
+6
View File
@@ -66,3 +66,9 @@ argv[3] = <-DSELECT_VECS='>
argv[1] = <TDEFAULTS>
argv[2] = <=>
argv[3] = <-DSELECT_VECS=\'>
a*b
ab
a?b
ab
a/b
ab
+11
View File
@@ -36,3 +36,14 @@ recho TDEFAULTS = ${selvecs:+-DSELECT_VECS="\\"}
recho TDEFAULTS = ${selvecs:+-DSELECT_VECS=\\}
recho TDEFAULTS = ${selvecs:+-DSELECT_VECS=\'}
recho TDEFAULTS = ${selvecs:+-DSELECT_VECS="\'"}
# more tests for bash-3.0 behavior
var="a*b" ; echo "${var//\\*/}"
var="a*b" ; echo "${var//\*/}"
var="a?b" ; echo "${var//\\?/}"
var="a?b" ; echo "${var//\?/}"
var="a/b" ; echo "${var//\\//}"
var="a/b" ; echo "${var//\//}"
+3
View File
@@ -51,3 +51,6 @@ after fff3: x=4
|0|12|
|y|
|y|
a=z
a=b
a=z
+3
View File
@@ -201,3 +201,6 @@ $THIS_SH ./varenv1.sub
# more tests; bugs in bash up to version 2.05a
$THIS_SH ./varenv2.sub
# make sure variable scoping is done right
tt() { typeset a=b;echo a=$a; };a=z;echo a=$a;tt;echo a=$a
+73 -46
View File
@@ -199,7 +199,7 @@ static void initialize_dynamic_variables __P((void));
static SHELL_VAR *hash_lookup __P((const char *, HASH_TABLE *));
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));
static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int, int));
static void free_variable_hash_data __P((PTR_T));
@@ -333,7 +333,7 @@ initialize_shell_variables (env, privmode)
#endif
else
{
temp_var = bind_variable (name, string);
temp_var = bind_variable (name, string, 0);
VSETATTR (temp_var, (att_exported | att_imported));
array_needs_making = 1;
}
@@ -350,7 +350,7 @@ initialize_shell_variables (env, privmode)
set_pwd ();
/* Set up initial value of $_ */
temp_var = bind_variable ("_", dollar_vars[0]);
temp_var = bind_variable ("_", dollar_vars[0], 0);
/* Remember this pid. */
dollar_dollar_pid = getpid ();
@@ -372,7 +372,7 @@ initialize_shell_variables (env, privmode)
{
char node_name[22];
qnx_nidtostr (getnid (), node_name, sizeof (node_name));
temp_var = bind_variable ("NODE", node_name);
temp_var = bind_variable ("NODE", node_name, 0);
set_auto_export (temp_var);
}
#endif
@@ -392,7 +392,7 @@ initialize_shell_variables (env, privmode)
set_if_not ("PS4", "+ ");
/* Don't allow IFS to be imported from the environment. */
temp_var = bind_variable ("IFS", " \t\n");
temp_var = bind_variable ("IFS", " \t\n", 0);
setifs (temp_var);
/* Magic machine types. Pretty convenient. */
@@ -411,9 +411,9 @@ initialize_shell_variables (env, privmode)
set_ppid ();
/* Initialize the `getopts' stuff. */
bind_variable ("OPTIND", "1");
bind_variable ("OPTIND", "1", 0);
getopts_reset (0);
bind_variable ("OPTERR", "1");
bind_variable ("OPTERR", "1", 0);
sh_opterr = 1;
if (login_shell == 1)
@@ -422,7 +422,7 @@ initialize_shell_variables (env, privmode)
/* Get the full pathname to THIS shell, and set the BASH variable
to it. */
name = get_bash_name ();
temp_var = bind_variable ("BASH", name);
temp_var = bind_variable ("BASH", name, 0);
free (name);
/* Make the exported environment variable SHELL be the user's login
@@ -432,13 +432,13 @@ initialize_shell_variables (env, privmode)
set_shell_var ();
/* Make a variable called BASH_VERSION which contains the version info. */
bind_variable ("BASH_VERSION", shell_version_string ());
bind_variable ("BASH_VERSION", shell_version_string (), 0);
#if defined (ARRAY_VARS)
make_vers_array ();
#endif
if (command_execution_string)
bind_variable ("BASH_EXECUTION_STRING", command_execution_string);
bind_variable ("BASH_EXECUTION_STRING", command_execution_string, 0);
/* Find out if we're supposed to be in Posix.2 mode via an
environment variable. */
@@ -556,7 +556,7 @@ set_home_var ()
temp_var = find_variable ("HOME");
if (temp_var == 0)
temp_var = bind_variable ("HOME", sh_get_home_dir ());
temp_var = bind_variable ("HOME", sh_get_home_dir (), 0);
#if 0
VSETATTR (temp_var, att_exported);
#endif
@@ -574,7 +574,7 @@ set_shell_var ()
{
if (current_user.shell == 0)
get_current_user_info ();
temp_var = bind_variable ("SHELL", current_user.shell);
temp_var = bind_variable ("SHELL", current_user.shell, 0);
}
#if 0
VSETATTR (temp_var, att_exported);
@@ -696,7 +696,7 @@ adjust_shell_level (change)
new_level[3] = '\0';
}
temp_var = bind_variable ("SHLVL", new_level);
temp_var = bind_variable ("SHLVL", new_level, 0);
set_auto_export (temp_var);
}
@@ -731,7 +731,7 @@ set_pwd ()
same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL))
{
set_working_directory (home_string);
temp_var = bind_variable ("PWD", home_string);
temp_var = bind_variable ("PWD", home_string, 0);
set_auto_export (temp_var);
}
else
@@ -739,7 +739,7 @@ set_pwd ()
temp_string = get_working_directory ("shell-init");
if (temp_string)
{
temp_var = bind_variable ("PWD", temp_string);
temp_var = bind_variable ("PWD", temp_string, 0);
set_auto_export (temp_var);
free (temp_string);
}
@@ -748,7 +748,7 @@ set_pwd ()
/* According to the Single Unix Specification, v2, $OLDPWD is an
`environment variable' and therefore should be auto-exported.
Make a dummy invisible variable for OLDPWD, and mark it as exported. */
temp_var = bind_variable ("OLDPWD", (char *)NULL);
temp_var = bind_variable ("OLDPWD", (char *)NULL, 0);
VSETATTR (temp_var, (att_exported | att_invisible));
}
@@ -763,7 +763,7 @@ set_ppid ()
temp_var = find_variable ("PPID");
if (temp_var)
VUNSETATTR (temp_var, (att_readonly | att_exported));
temp_var = bind_variable ("PPID", name);
temp_var = bind_variable ("PPID", name, 0);
VSETATTR (temp_var, (att_readonly | att_integer));
}
@@ -777,7 +777,7 @@ uidset ()
v = find_variable ("UID");
if (v == 0)
{
v = bind_variable ("UID", b);
v = bind_variable ("UID", b, 0);
VSETATTR (v, (att_readonly | att_integer));
}
@@ -787,7 +787,7 @@ uidset ()
v = find_variable ("EUID");
if (v == 0)
{
v = bind_variable ("EUID", b);
v = bind_variable ("EUID", b, 0);
VSETATTR (v, (att_readonly | att_integer));
}
}
@@ -830,10 +830,10 @@ sh_set_lines_and_columns (lines, cols)
char val[INT_STRLEN_BOUND(int) + 1], *v;
v = inttostr (lines, val, sizeof (val));
bind_variable ("LINES", v);
bind_variable ("LINES", v, 0);
v = inttostr (cols, val, sizeof (val));
bind_variable ("COLUMNS", v);
bind_variable ("COLUMNS", v, 0);
}
/* **************************************************************** */
@@ -983,7 +983,7 @@ print_var_function (var)
#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \
do \
{ \
v = bind_variable (var, (val)); \
v = bind_variable (var, (val), 0); \
v->dynamic_value = gfunc; \
v->assign_func = afunc; \
} \
@@ -1589,7 +1589,7 @@ set_if_not (name, value)
v = find_variable (name);
if (v == 0)
v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH);
v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0);
return (v);
}
@@ -1643,7 +1643,7 @@ make_local_variable (name)
}
if (old_var == 0)
new_var = bind_variable_internal (name, "", vc->table, HASH_NOSRCH);
new_var = bind_variable_internal (name, "", vc->table, HASH_NOSRCH, 0);
else
{
new_var = make_new_variable (name, vc->table);
@@ -1758,13 +1758,14 @@ make_new_array_variable (name)
#endif
char *
make_variable_value (var, value)
make_variable_value (var, value, flags)
SHELL_VAR *var;
char *value;
int flags;
{
char *retval;
intmax_t lval;
int expok;
char *retval, *oval;
intmax_t lval, rval;
int expok, olen;
/* If this variable has had its type set to integer (via `declare -i'),
then do expression evaluation on it and store the result. The
@@ -1773,14 +1774,34 @@ make_variable_value (var, value)
evaluation done. */
if (integer_p (var))
{
lval = evalexp (value, &expok);
if (flags & ASS_APPEND)
{
oval = value_cell (var);
lval = evalexp (oval, &expok); /* ksh93 seems to do this */
if (expok == 0)
jump_to_top_level (DISCARD);
}
rval = evalexp (value, &expok);
if (expok == 0)
jump_to_top_level (DISCARD);
retval = itos (lval);
if (flags & ASS_APPEND)
rval += lval;
retval = itos (rval);
}
else if (value)
{
if (*value)
if (flags & ASS_APPEND)
{
oval = value_cell (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);
}
else if (*value)
retval = savestring (value);
else
{
@@ -1797,11 +1818,11 @@ make_variable_value (var, value)
/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the
temporary environment (but usually is not). */
static SHELL_VAR *
bind_variable_internal (name, value, table, hflags)
bind_variable_internal (name, value, table, hflags, aflags)
const char *name;
char *value;
HASH_TABLE *table;
int hflags;
int hflags, aflags;
{
char *newval;
SHELL_VAR *entry;
@@ -1811,7 +1832,7 @@ bind_variable_internal (name, value, table, hflags)
if (entry == 0)
{
entry = make_new_variable (name, table);
var_setvalue (entry, make_variable_value (entry, value));
var_setvalue (entry, make_variable_value (entry, value, 0)); /* XXX */
}
else if (entry->assign_func) /* array vars have assign functions now */
{
@@ -1830,7 +1851,7 @@ bind_variable_internal (name, value, table, hflags)
/* Variables which are bound are visible. */
VUNSETATTR (entry, att_invisible);
newval = make_variable_value (entry, value);
newval = make_variable_value (entry, value, aflags); /* XXX */
/* Invalidate any cached export string */
INVALIDATE_EXPORTSTR (entry);
@@ -1867,9 +1888,10 @@ bind_variable_internal (name, value, table, hflags)
first, then we bind into shell_variables. */
SHELL_VAR *
bind_variable (name, value)
bind_variable (name, value, flags)
const char *name;
char *value;
int flags;
{
SHELL_VAR *v;
VAR_CONTEXT *vc;
@@ -1896,10 +1918,10 @@ bind_variable (name, value)
{
v = hash_lookup (name, vc->table);
if (v)
return (bind_variable_internal (name, value, vc->table, 0));
return (bind_variable_internal (name, value, vc->table, 0, flags));
}
}
return (bind_variable_internal (name, value, global_variables->table, 0));
return (bind_variable_internal (name, value, global_variables->table, 0, flags));
}
/* Make VAR, a simple shell variable, have value VALUE. Once assigned a
@@ -1908,15 +1930,16 @@ bind_variable (name, value)
all modified variables should be exported, mark the variable for export
and note that the export environment needs to be recreated. */
SHELL_VAR *
bind_variable_value (var, value)
bind_variable_value (var, value, aflags)
SHELL_VAR *var;
char *value;
int aflags;
{
char *t;
VUNSETATTR (var, att_invisible);
t = make_variable_value (var, value);
t = make_variable_value (var, value, aflags);
FREE (value_cell (var));
var_setvalue (var, t);
@@ -1972,10 +1995,10 @@ bind_int_variable (lhs, rhs)
#if defined (ARRAY_VARS)
if (isarr)
v = assign_array_element (lhs, rhs);
v = assign_array_element (lhs, rhs, 0);
else
#endif
v = bind_variable (lhs, rhs);
v = bind_variable (lhs, rhs, 0);
if (isint)
VSETATTR (v, att_integer);
@@ -2092,6 +2115,10 @@ assign_in_env (word)
{
name[offset] = 0;
/* ignore the `+' when assigning temporary environment */
if (name[offset - 1] == '+')
name[offset - 1] = '\0';
var = find_variable (name);
if (var && (readonly_p (var) || noassign_p (var)))
{
@@ -2407,7 +2434,7 @@ delete_all_variables (hashed_vars)
entry = find_variable (name); \
if (!entry) \
{ \
entry = bind_variable (name, ""); \
entry = bind_variable (name, "", 0); \
if (!no_invisible_vars) entry->attributes |= att_invisible; \
} \
} \
@@ -2849,7 +2876,7 @@ push_temp_var (data)
binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS);
}
v = bind_variable_internal (var->name, value_cell (var), binding_table, 0);
v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, 0);
/* XXX - should we set the context here? It shouldn't matter because of how
assign_in_env works, but might want to check. */
@@ -3367,7 +3394,7 @@ push_func_var (data)
if (tempvar_p (var) && (posixly_correct || (var->attributes & att_propagate)))
{
/* XXX - should we set v->context here? */
v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0);
v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
if (shell_variables == global_variables)
var->attributes &= ~(att_tempvar|att_propagate);
else
@@ -3455,7 +3482,7 @@ push_exported_var (data)
#endif
{
var->attributes &= ~att_tempvar; /* XXX */
v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0);
v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
if (shell_variables == global_variables)
var->attributes &= ~att_propagate;
v->attributes |= var->attributes;
+82 -47
View File
@@ -199,7 +199,7 @@ static void initialize_dynamic_variables __P((void));
static SHELL_VAR *hash_lookup __P((const char *, HASH_TABLE *));
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));
static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int, int));
static void free_variable_hash_data __P((PTR_T));
@@ -320,7 +320,7 @@ initialize_shell_variables (env, privmode)
#if defined (ARRAY_VARS)
# if 0
/* Array variables may not yet be exported. */
else if (*string == '(' && string[1] == '[' && xstrchr (string, ')'))
else if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')')
{
string_length = 1;
temp_string = extract_array_assignment_list (string, &string_length);
@@ -333,7 +333,7 @@ initialize_shell_variables (env, privmode)
#endif
else
{
temp_var = bind_variable (name, string);
temp_var = bind_variable (name, string, 0);
VSETATTR (temp_var, (att_exported | att_imported));
array_needs_making = 1;
}
@@ -350,7 +350,7 @@ initialize_shell_variables (env, privmode)
set_pwd ();
/* Set up initial value of $_ */
temp_var = bind_variable ("_", dollar_vars[0]);
temp_var = bind_variable ("_", dollar_vars[0], 0);
/* Remember this pid. */
dollar_dollar_pid = getpid ();
@@ -372,7 +372,7 @@ initialize_shell_variables (env, privmode)
{
char node_name[22];
qnx_nidtostr (getnid (), node_name, sizeof (node_name));
temp_var = bind_variable ("NODE", node_name);
temp_var = bind_variable ("NODE", node_name, 0);
set_auto_export (temp_var);
}
#endif
@@ -392,7 +392,7 @@ initialize_shell_variables (env, privmode)
set_if_not ("PS4", "+ ");
/* Don't allow IFS to be imported from the environment. */
temp_var = bind_variable ("IFS", " \t\n");
temp_var = bind_variable ("IFS", " \t\n", 0);
setifs (temp_var);
/* Magic machine types. Pretty convenient. */
@@ -411,9 +411,9 @@ initialize_shell_variables (env, privmode)
set_ppid ();
/* Initialize the `getopts' stuff. */
bind_variable ("OPTIND", "1");
bind_variable ("OPTIND", "1", 0);
getopts_reset (0);
bind_variable ("OPTERR", "1");
bind_variable ("OPTERR", "1", 0);
sh_opterr = 1;
if (login_shell == 1)
@@ -422,7 +422,7 @@ initialize_shell_variables (env, privmode)
/* Get the full pathname to THIS shell, and set the BASH variable
to it. */
name = get_bash_name ();
temp_var = bind_variable ("BASH", name);
temp_var = bind_variable ("BASH", name, 0);
free (name);
/* Make the exported environment variable SHELL be the user's login
@@ -432,13 +432,13 @@ initialize_shell_variables (env, privmode)
set_shell_var ();
/* Make a variable called BASH_VERSION which contains the version info. */
bind_variable ("BASH_VERSION", shell_version_string ());
bind_variable ("BASH_VERSION", shell_version_string (), 0);
#if defined (ARRAY_VARS)
make_vers_array ();
#endif
if (command_execution_string)
bind_variable ("BASH_EXECUTION_STRING", command_execution_string);
bind_variable ("BASH_EXECUTION_STRING", command_execution_string, 0);
/* Find out if we're supposed to be in Posix.2 mode via an
environment variable. */
@@ -556,7 +556,7 @@ set_home_var ()
temp_var = find_variable ("HOME");
if (temp_var == 0)
temp_var = bind_variable ("HOME", sh_get_home_dir ());
temp_var = bind_variable ("HOME", sh_get_home_dir (), 0);
#if 0
VSETATTR (temp_var, att_exported);
#endif
@@ -574,7 +574,7 @@ set_shell_var ()
{
if (current_user.shell == 0)
get_current_user_info ();
temp_var = bind_variable ("SHELL", current_user.shell);
temp_var = bind_variable ("SHELL", current_user.shell, 0);
}
#if 0
VSETATTR (temp_var, att_exported);
@@ -696,7 +696,7 @@ adjust_shell_level (change)
new_level[3] = '\0';
}
temp_var = bind_variable ("SHLVL", new_level);
temp_var = bind_variable ("SHLVL", new_level, 0);
set_auto_export (temp_var);
}
@@ -731,7 +731,7 @@ set_pwd ()
same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL))
{
set_working_directory (home_string);
temp_var = bind_variable ("PWD", home_string);
temp_var = bind_variable ("PWD", home_string, 0);
set_auto_export (temp_var);
}
else
@@ -739,7 +739,7 @@ set_pwd ()
temp_string = get_working_directory ("shell-init");
if (temp_string)
{
temp_var = bind_variable ("PWD", temp_string);
temp_var = bind_variable ("PWD", temp_string, 0);
set_auto_export (temp_var);
free (temp_string);
}
@@ -748,7 +748,7 @@ set_pwd ()
/* According to the Single Unix Specification, v2, $OLDPWD is an
`environment variable' and therefore should be auto-exported.
Make a dummy invisible variable for OLDPWD, and mark it as exported. */
temp_var = bind_variable ("OLDPWD", (char *)NULL);
temp_var = bind_variable ("OLDPWD", (char *)NULL, 0);
VSETATTR (temp_var, (att_exported | att_invisible));
}
@@ -763,7 +763,7 @@ set_ppid ()
temp_var = find_variable ("PPID");
if (temp_var)
VUNSETATTR (temp_var, (att_readonly | att_exported));
temp_var = bind_variable ("PPID", name);
temp_var = bind_variable ("PPID", name, 0);
VSETATTR (temp_var, (att_readonly | att_integer));
}
@@ -777,7 +777,7 @@ uidset ()
v = find_variable ("UID");
if (v == 0)
{
v = bind_variable ("UID", b);
v = bind_variable ("UID", b, 0);
VSETATTR (v, (att_readonly | att_integer));
}
@@ -787,7 +787,7 @@ uidset ()
v = find_variable ("EUID");
if (v == 0)
{
v = bind_variable ("EUID", b);
v = bind_variable ("EUID", b, 0);
VSETATTR (v, (att_readonly | att_integer));
}
}
@@ -830,10 +830,10 @@ sh_set_lines_and_columns (lines, cols)
char val[INT_STRLEN_BOUND(int) + 1], *v;
v = inttostr (lines, val, sizeof (val));
bind_variable ("LINES", v);
bind_variable ("LINES", v, 0);
v = inttostr (cols, val, sizeof (val));
bind_variable ("COLUMNS", v);
bind_variable ("COLUMNS", v, 0);
}
/* **************************************************************** */
@@ -983,7 +983,7 @@ print_var_function (var)
#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \
do \
{ \
v = bind_variable (var, (val)); \
v = bind_variable (var, (val), 0); \
v->dynamic_value = gfunc; \
v->assign_func = afunc; \
} \
@@ -1589,7 +1589,7 @@ set_if_not (name, value)
v = find_variable (name);
if (v == 0)
v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH);
v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0);
return (v);
}
@@ -1643,7 +1643,7 @@ make_local_variable (name)
}
if (old_var == 0)
new_var = bind_variable_internal (name, "", vc->table, HASH_NOSRCH);
new_var = bind_variable_internal (name, "", vc->table, HASH_NOSRCH, 0);
else
{
new_var = make_new_variable (name, vc->table);
@@ -1758,13 +1758,14 @@ make_new_array_variable (name)
#endif
char *
make_variable_value (var, value)
make_variable_value (var, value, flags)
SHELL_VAR *var;
char *value;
int flags;
{
char *retval;
intmax_t lval;
int expok;
char *retval, *oval;
intmax_t lval, rval;
int expok, olen;
/* If this variable has had its type set to integer (via `declare -i'),
then do expression evaluation on it and store the result. The
@@ -1773,14 +1774,34 @@ make_variable_value (var, value)
evaluation done. */
if (integer_p (var))
{
lval = evalexp (value, &expok);
if (flags & ASS_APPEND)
{
oval = value_cell (var);
lval = evalexp (oval, &expok); /* ksh93 seems to do this */
if (expok == 0)
jump_to_top_level (DISCARD);
}
rval = evalexp (value, &expok);
if (expok == 0)
jump_to_top_level (DISCARD);
retval = itos (lval);
if (flags & ASS_APPEND)
rval += lval;
retval = itos (rval);
}
else if (value)
{
if (*value)
if (flags & ASS_APPEND)
{
oval = value_cell (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);
}
else if (*value)
retval = savestring (value);
else
{
@@ -1797,11 +1818,11 @@ make_variable_value (var, value)
/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the
temporary environment (but usually is not). */
static SHELL_VAR *
bind_variable_internal (name, value, table, hflags)
bind_variable_internal (name, value, table, hflags, aflags)
const char *name;
char *value;
HASH_TABLE *table;
int hflags;
int hflags, aflags;
{
char *newval;
SHELL_VAR *entry;
@@ -1811,7 +1832,7 @@ bind_variable_internal (name, value, table, hflags)
if (entry == 0)
{
entry = make_new_variable (name, table);
var_setvalue (entry, make_variable_value (entry, value));
var_setvalue (entry, make_variable_value (entry, value, 0)); /* XXX */
}
else if (entry->assign_func) /* array vars have assign functions now */
{
@@ -1830,7 +1851,7 @@ bind_variable_internal (name, value, table, hflags)
/* Variables which are bound are visible. */
VUNSETATTR (entry, att_invisible);
newval = make_variable_value (entry, value);
newval = make_variable_value (entry, value, aflags); /* XXX */
/* Invalidate any cached export string */
INVALIDATE_EXPORTSTR (entry);
@@ -1867,9 +1888,10 @@ bind_variable_internal (name, value, table, hflags)
first, then we bind into shell_variables. */
SHELL_VAR *
bind_variable (name, value)
bind_variable (name, value, flags)
const char *name;
char *value;
int flags;
{
SHELL_VAR *v;
VAR_CONTEXT *vc;
@@ -1896,10 +1918,10 @@ bind_variable (name, value)
{
v = hash_lookup (name, vc->table);
if (v)
return (bind_variable_internal (name, value, vc->table, 0));
return (bind_variable_internal (name, value, vc->table, 0, flags));
}
}
return (bind_variable_internal (name, value, global_variables->table, 0));
return (bind_variable_internal (name, value, global_variables->table, 0, flags));
}
/* Make VAR, a simple shell variable, have value VALUE. Once assigned a
@@ -1908,15 +1930,16 @@ bind_variable (name, value)
all modified variables should be exported, mark the variable for export
and note that the export environment needs to be recreated. */
SHELL_VAR *
bind_variable_value (var, value)
bind_variable_value (var, value, aflags)
SHELL_VAR *var;
char *value;
int aflags;
{
char *t;
VUNSETATTR (var, att_invisible);
t = make_variable_value (var, value);
t = make_variable_value (var, value, aflags);
FREE (value_cell (var));
var_setvalue (var, t);
@@ -1972,10 +1995,10 @@ bind_int_variable (lhs, rhs)
#if defined (ARRAY_VARS)
if (isarr)
v = assign_array_element (lhs, rhs);
v = assign_array_element (lhs, rhs, 0);
else
#endif
v = bind_variable (lhs, rhs);
v = bind_variable (lhs, rhs, 0);
if (isint)
VSETATTR (v, att_integer);
@@ -2073,6 +2096,8 @@ bind_function_def (name, value)
HASH_TABLE (temporary_env). The functions in execute_cmd.c are
responsible for moving the main temporary env to one of the other
temporary environments. The expansion code in subst.c calls this. */
/* XXX - changes needed for `+=' */
int
assign_in_env (word)
WORD_DESC *word;
@@ -2092,6 +2117,10 @@ assign_in_env (word)
{
name[offset] = 0;
/* ignore the `+' when assigning temporary environment */
if (name[offset - 1] == '+')
name[offset - 1] = '\0';
var = find_variable (name);
if (var && (readonly_p (var) || noassign_p (var)))
{
@@ -2407,7 +2436,7 @@ delete_all_variables (hashed_vars)
entry = find_variable (name); \
if (!entry) \
{ \
entry = bind_variable (name, ""); \
entry = bind_variable (name, "", 0); \
if (!no_invisible_vars) entry->attributes |= att_invisible; \
} \
} \
@@ -2849,7 +2878,7 @@ push_temp_var (data)
binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS);
}
v = bind_variable_internal (var->name, value_cell (var), binding_table, 0);
v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, 0);
/* XXX - should we set the context here? It shouldn't matter because of how
assign_in_env works, but might want to check. */
@@ -3367,7 +3396,7 @@ push_func_var (data)
if (tempvar_p (var) && (posixly_correct || (var->attributes & att_propagate)))
{
/* XXX - should we set v->context here? */
v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0);
v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
if (shell_variables == global_variables)
var->attributes &= ~(att_tempvar|att_propagate);
else
@@ -3446,10 +3475,16 @@ push_exported_var (data)
/* If a temp var had its export attribute set, or it's marked to be
propagated, bind it in the previous scope before disposing it. */
/* XXX - This isn't exactly right, because all tempenv variables have the
export attribute set. */
#if 0
if (exported_p (var) || (var->attributes & att_propagate))
#else
if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate))
#endif
{
var->attributes &= ~att_tempvar; /* XXX */
v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0);
v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
if (shell_variables == global_variables)
var->attributes &= ~att_propagate;
v->attributes |= var->attributes;
+4 -4
View File
@@ -1,6 +1,6 @@
/* variables.h -- data structures for shell variables. */
/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -224,7 +224,7 @@ extern SHELL_VAR *find_variable_internal __P((const char *, int));
extern SHELL_VAR *find_tempenv_variable __P((const char *));
extern SHELL_VAR *copy_variable __P((SHELL_VAR *));
extern SHELL_VAR *make_local_variable __P((const char *));
extern SHELL_VAR *bind_variable __P((const char *, char *));
extern SHELL_VAR *bind_variable __P((const char *, char *, int));
extern SHELL_VAR *bind_function __P((const char *, COMMAND *));
extern void bind_function_def __P((const char *, FUNCTION_DEF *));
@@ -250,9 +250,9 @@ extern char **add_or_supercede_exported_var __P((char *, int));
extern char *get_variable_value __P((SHELL_VAR *));
extern char *get_string_value __P((const char *));
extern char *sh_get_env_value __P((const char *));
extern char *make_variable_value __P((SHELL_VAR *, char *));
extern char *make_variable_value __P((SHELL_VAR *, char *, int));
extern SHELL_VAR *bind_variable_value __P((SHELL_VAR *, char *));
extern SHELL_VAR *bind_variable_value __P((SHELL_VAR *, char *, int));
extern SHELL_VAR *bind_int_variable __P((char *, char *));
extern SHELL_VAR *bind_var_to_int __P((char *, intmax_t));
+5 -4
View File
@@ -224,7 +224,7 @@ extern SHELL_VAR *find_variable_internal __P((const char *, int));
extern SHELL_VAR *find_tempenv_variable __P((const char *));
extern SHELL_VAR *copy_variable __P((SHELL_VAR *));
extern SHELL_VAR *make_local_variable __P((const char *));
extern SHELL_VAR *bind_variable __P((const char *, char *));
extern SHELL_VAR *bind_variable __P((const char *, char *, int));
extern SHELL_VAR *bind_function __P((const char *, COMMAND *));
extern void bind_function_def __P((const char *, FUNCTION_DEF *));
@@ -250,13 +250,14 @@ extern char **add_or_supercede_exported_var __P((char *, int));
extern char *get_variable_value __P((SHELL_VAR *));
extern char *get_string_value __P((const char *));
extern char *sh_get_env_value __P((const char *));
extern char *make_variable_value __P((SHELL_VAR *, char *));
extern char *make_variable_value __P((SHELL_VAR *, char *, int));
extern SHELL_VAR *bind_variable_value __P((SHELL_VAR *, char *));
extern SHELL_VAR *bind_variable_value __P((SHELL_VAR *, char *, int));
extern SHELL_VAR *bind_int_variable __P((char *, char *));
extern SHELL_VAR *bind_var_to_int __P((char *, intmax_t));
extern int assign_in_env __P((const char *));
extern int assign_in_env __P((WORD_DESC *));
extern int unbind_variable __P((const char *));
extern int unbind_func __P((const char *));
extern int unbind_function_def __P((const char *));