mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-29 16:39:53 +02:00
commit bash-20041104 snapshot
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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++;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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));
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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';
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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--;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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. */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 ':':
|
||||
|
||||
@@ -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 *));
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -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}
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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""
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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//\//}"
|
||||
|
||||
@@ -51,3 +51,6 @@ after fff3: x=4
|
||||
|0|12|
|
||||
|y|
|
||||
|y|
|
||||
a=z
|
||||
a=b
|
||||
a=z
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 *));
|
||||
|
||||
Reference in New Issue
Block a user