commit bash-20121221 snapshot

This commit is contained in:
Chet Ramey
2013-01-03 10:47:42 -05:00
parent 77b3aacbdf
commit 36eb585cfa
51 changed files with 33625 additions and 656 deletions
+2 -2
View File
@@ -513,10 +513,10 @@ declare_internal (list, local_var)
#endif
if (offset)
var = bind_variable (name, "", 0);
var = mkglobal ? bind_global_variable (name, "", 0) : bind_variable (name, "", 0);
else
{
var = bind_variable (name, (char *)NULL, 0);
var = mkglobal ? bind_global_variable (name, (char *)NULL, 0) : bind_variable (name, (char *)NULL, 0);
VSETATTR (var, att_invisible);
}
}
+694
View File
@@ -0,0 +1,694 @@
This file is declare.def, from which is created declare.c.
It implements the builtins "declare" and "local" in Bash.
Copyright (C) 1987-2012 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES declare.c
$BUILTIN declare
$FUNCTION declare_builtin
$SHORT_DOC declare [-aAfFgilnrtux] [-p] [name[=value] ...]
Set variable values and attributes.
Declare variables and give them attributes. If no NAMEs are given,
display the attributes and values of all variables.
Options:
-f restrict action or display to function names and definitions
-F restrict display to function names only (plus line number and
source file when debugging)
-g create global variables when used in a shell function; otherwise
ignored
-p display the attributes and value of each NAME
Options which set attributes:
-a to make NAMEs indexed arrays (if supported)
-A to make NAMEs associative arrays (if supported)
-i to make NAMEs have the `integer' attribute
-l to convert NAMEs to lower case on assignment
-n make NAME a reference to the variable named by its value
-r to make NAMEs readonly
-t to make NAMEs have the `trace' attribute
-u to convert NAMEs to upper case on assignment
-x to make NAMEs export
Using `+' instead of `-' turns off the given attribute.
Variables with the integer attribute have arithmetic evaluation (see
the `let' command) performed when the variable is assigned a value.
When used in a function, `declare' makes NAMEs local, as with the `local'
command. The `-g' option suppresses this behavior.
Exit Status:
Returns success unless an invalid option is supplied or a variable
assignment error occurs.
$END
$BUILTIN typeset
$FUNCTION declare_builtin
$SHORT_DOC typeset [-aAfFgilrtux] [-p] name[=value] ...
Set variable values and attributes.
Obsolete. See `help 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;
extern int posixly_correct;
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 [option] name[=value] ...
Define local variables.
Create a local variable called NAME, and give it VALUE. OPTION can
be any option accepted by `declare'.
Local variables can only be used within a function; they are visible
only to the function where they are defined and its children.
Exit Status:
Returns success unless an invalid option is supplied, a variable
assignment error occurs, or the shell is not executing a function.
$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 "+acfgilnprtuxAF"
#else
# define DECLARE_OPTS "+cfgilnprtuxF"
#endif
/* The workhorse function. */
static int
declare_internal (list, local_var)
register WORD_LIST *list;
int local_var;
{
int flags_on, flags_off, *flags;
int any_failed, assign_error, pflag, nodefs, opt, mkglobal, onref, offref;
char *t, *subscript_start;
SHELL_VAR *var, *refvar;
FUNCTION_DEF *shell_fn;
flags_on = flags_off = any_failed = assign_error = pflag = nodefs = mkglobal = 0;
refvar = (SHELL_VAR *)NULL;
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;
break;
#else
builtin_usage ();
return (EX_USAGE);
#endif
case 'A':
#if defined (ARRAY_VARS)
*flags |= att_assoc;
break;
#else
builtin_usage ();
return (EX_USAGE);
#endif
case 'p':
if (local_var == 0)
pflag++;
break;
case 'F':
nodefs++;
*flags |= att_function;
break;
case 'f':
*flags |= att_function;
break;
case 'g':
if (flags == &flags_on)
mkglobal = 1;
break;
case 'i':
*flags |= att_integer;
break;
case 'n':
*flags |= att_nameref;
break;
case 'r':
*flags |= att_readonly;
break;
case 't':
*flags |= att_trace;
break;
case 'x':
*flags |= att_exported;
array_needs_making = 1;
break;
#if defined (CASEMOD_ATTRS)
# if defined (CASEMOD_CAPCASE)
case 'c':
*flags |= att_capcase;
if (flags == &flags_on)
flags_off |= att_uppercase|att_lowercase;
break;
# endif
case 'l':
*flags |= att_lowercase;
if (flags == &flags_on)
flags_off |= att_capcase|att_uppercase;
break;
case 'u':
*flags |= att_uppercase;
if (flags == &flags_on)
flags_off |= att_capcase|att_lowercase;
break;
#endif /* CASEMOD_ATTRS */
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 -[aAfFirtx] */
{
/* 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 (pflag && (flags_on == 0 || flags_on == att_function))
show_all_var_attributes (flags_on == 0, nodefs);
else if (flags_on == 0)
return (set_builtin ((WORD_LIST *)NULL));
else
set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
return (sh_chkwrite (EXECUTION_SUCCESS));
}
if (pflag) /* declare -p [-aAfFirtx] 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 (sh_chkwrite (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 [-aAfFirx] 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 [-aAfFirx] name=value */
{
name[offset] = '\0';
value = name + offset + 1;
if (name[offset - 1] == '+')
{
aflags |= ASS_APPEND;
name[offset - 1] = '\0';
}
}
else
value = "";
/* Do some lexical error checking on the LHS and RHS of the assignment
that is specific to nameref variables. */
if (flags_on & att_nameref)
{
if (valid_array_reference (name))
{
builtin_error (_("%s: reference variable cannot be an array"), name);
assign_error++;
NEXT_VARIABLE ();
}
else if (STREQ (name, value))
{
builtin_error (_("%s: nameref variable self references not allowed"), name);
assign_error++;
NEXT_VARIABLE ();
}
}
#if defined (ARRAY_VARS)
compound_array_assign = simple_array_assign = 0;
subscript_start = (char *)NULL;
if (t = strchr (name, '[')) /* ] */
{
/* If offset != 0 we have already validated any array reference */
if (offset == 0 && valid_array_reference (name) == 0)
{
sh_invalidid (name);
assign_error++;
NEXT_VARIABLE ();
}
subscript_start = t;
*t = '\0';
making_array_special = 1;
}
else
making_array_special = 0;
#endif
/* If we're in posix mode or not looking for a shell function (since
shell function names don't have to be valid identifiers when the
shell's not in posix mode), check whether or not the argument is a
valid, well-formed shell identifier. */
if ((posixly_correct || (flags_on & att_function) == 0) && 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. */
refvar = (SHELL_VAR *)NULL;
if (variable_context && mkglobal == 0 && ((flags_on & att_function) == 0))
{
#if defined (ARRAY_VARS)
if (flags_on & att_assoc)
var = make_local_assoc_variable (name);
else if ((flags_on & att_array) || making_array_special)
var = make_local_array_variable (name, making_array_special);
else
#endif
#if 0
/* XXX - this doesn't work right yet. */
/* See below for rationale for doing this. */
if (flags_on & att_nameref)
{
/* See if we are trying to modify an existing nameref variable */
var = find_variable_last_nameref (name);
if (var && nameref_p (var) == 0)
var = make_local_variable (name);
}
else if (flags_off & att_nameref)
{
var = (SHELL_VAR *)NULL;
/* See if we are trying to modify an existing nameref variable */
refvar = find_variable_last_nameref (name);
if (refvar && nameref_p (refvar) == 0)
refvar = 0;
if (refvar)
var = make_local_variable (nameref_cell (refvar));
if (var == 0)
var = make_local_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), FUNC_MULTILINE|FUNC_EXTERNAL);
printf ("%s\n", t);
any_failed = sh_chkwrite (any_failed);
}
}
else /* declare -[fF] -[rx] name [name...] */
{
VSETATTR (var, flags_on);
VUNSETATTR (var, flags_off);
}
}
else
any_failed++;
NEXT_VARIABLE ();
}
}
else /* declare -[aAirx] name [name...] */
{
/* Non-null if we just created or fetched a local variable. */
/* Here's what ksh93 seems to do. If we are modifying an existing
nameref variable, we don't follow the nameref chain past the last
nameref, and we set the nameref variable's value so future
references to that variable will return the value of the variable
we're assigning right now. */
if (var == 0 && (flags_on & att_nameref))
{
/* See if we are trying to modify an existing nameref variable */
var = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name);
if (var && nameref_p (var) == 0)
var = 0;
}
/* However, if we're turning off the nameref attribute on an existing
nameref variable, we first follow the nameref chain to the end,
modify the value of the variable this nameref variable references,
*CHANGING ITS VALUE AS A SIDE EFFECT* then turn off the nameref
flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */
else if (var == 0 && (flags_off & att_nameref))
{
/* See if we are trying to modify an existing nameref variable */
refvar = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name);
if (refvar && nameref_p (refvar) == 0)
refvar = 0;
if (refvar)
var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
}
if (var == 0)
var = mkglobal ? find_global_variable (name) : find_variable (name);
if (var == 0)
{
#if defined (ARRAY_VARS)
if (flags_on & att_assoc)
{
var = make_new_assoc_variable (name);
if (offset == 0)
VSETATTR (var, att_invisible);
}
else if ((flags_on & att_array) || making_array_special)
{
var = make_new_array_variable (name);
if (offset == 0)
VSETATTR (var, att_invisible);
}
else
#endif
if (offset)
var = bind_variable (name, "", 0);
else
{
var = bind_variable (name, (char *)NULL, 0);
VSETATTR (var, att_invisible);
}
}
/* Can't take an existing array variable and make it a nameref */
else if ((array_p (var) || assoc_p (var)) && (flags_on & att_nameref))
{
builtin_error (_("%s: reference variable cannot be an array"), name);
assign_error++;
NEXT_VARIABLE ();
}
/* 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|att_assoc)) || array_p (var) || assoc_p (var)) && offset)
{
int vlen;
vlen = STRLEN (value);
if (value[0] == '(' && value[vlen-1] == ')')
compound_array_assign = 1;
else
simple_array_assign = 1;
}
/* Cannot use declare +a name or declare +A name to remove an
array variable. */
if (((flags_off & att_array) && array_p (var)) || ((flags_off & att_assoc) && assoc_p (var)))
{
builtin_error (_("%s: cannot destroy array variables in this way"), name);
any_failed++;
NEXT_VARIABLE ();
}
if ((flags_on & att_array) && assoc_p (var))
{
builtin_error (_("%s: cannot convert associative to indexed array"), name);
any_failed++;
NEXT_VARIABLE ();
}
if ((flags_on & att_assoc) && array_p (var))
{
builtin_error (_("%s: cannot convert indexed to associative array"), name);
any_failed++;
NEXT_VARIABLE ();
}
/* declare -A name[[n]] makes name an associative array variable. */
if (flags_on & att_assoc)
{
if (assoc_p (var) == 0)
var = convert_var_to_assoc (var);
}
/* declare -a name[[n]] or declare name[n] makes name an indexed
array variable. */
else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0 && assoc_p (var) == 0)
var = convert_var_to_array (var);
#endif /* ARRAY_VARS */
/* XXX - we note that we are turning on nameref attribute and defer
setting it until the assignment has been made so we don't do an
inadvertent nameref lookup. Might have to do the same thing for
flags_off&att_nameref. */
/* XXX - ksh93 makes it an error to set a readonly nameref variable
using a single typeset command. */
onref = (flags_on & att_nameref);
flags_on &= ~att_nameref;
if (array_p (var) || assoc_p (var)
|| (offset && compound_array_assign)
|| simple_array_assign)
onref = 0; /* array variables may not be namerefs */
/* ksh93 seems to do this */
offref = (flags_off & att_nameref);
flags_off &= ~att_nameref;
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 [-aA] name[N]=value */
*subscript_start = '['; /* ] */
var = assign_array_element (name, value, 0); /* XXX - not aflags */
*subscript_start = '\0';
if (var == 0) /* some kind of assignment error */
{
assign_error++;
flags_on |= onref;
flags_off |= offref;
NEXT_VARIABLE ();
}
}
else if (simple_array_assign)
{
/* let bind_{array,assoc}_variable take care of this. */
if (assoc_p (var))
bind_assoc_variable (var, name, savestring ("0"), value, aflags);
else
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);
}
}
/* Turn on nameref attribute we deferred above. */
/* XXX - should we turn on the noassign attribute for consistency with
ksh93 when we turn on the nameref attribute? */
VSETATTR (var, onref);
flags_on |= onref;
VUNSETATTR (var, offref);
flags_off |= offref;
/* Yuck. ksh93 compatibility */
if (refvar)
VUNSETATTR (refvar, flags_off);
stupidly_hack_special_variables (name);
NEXT_VARIABLE ();
}
return (assign_error ? EX_BADASSIGN
: ((any_failed == 0) ? EXECUTION_SUCCESS
: EXECUTION_FAILURE));
}
+1 -1
View File
@@ -251,7 +251,7 @@ file_error_and_exit:
if (flags & FEVAL_BUILTIN)
result = EXECUTION_SUCCESS;
return_val = setjmp (return_catch);
return_val = setjmp_nosigs (return_catch);
/* If `return' was seen outside of a function, but in the script, then
force parse_and_execute () to clean up. */
+348
View File
@@ -0,0 +1,348 @@
/* evalfile.c - read and evaluate commands from a file or file descriptor */
/* Copyright (C) 1996-2009 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashtypes.h"
#include "posixstat.h"
#include "filecntl.h"
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../jobs.h"
#include "../builtins.h"
#include "../flags.h"
#include "../input.h"
#include "../execute_cmd.h"
#include "../trap.h"
#if defined (HISTORY)
# include "../bashhist.h"
#endif
#include <typemax.h>
#include "common.h"
#if !defined (errno)
extern int errno;
#endif
/* Flags for _evalfile() */
#define FEVAL_ENOENTOK 0x001
#define FEVAL_BUILTIN 0x002
#define FEVAL_UNWINDPROT 0x004
#define FEVAL_NONINT 0x008
#define FEVAL_LONGJMP 0x010
#define FEVAL_HISTORY 0x020
#define FEVAL_CHECKBINARY 0x040
#define FEVAL_REGFILE 0x080
#define FEVAL_NOPUSHARGS 0x100
extern int posixly_correct;
extern int indirection_level, subshell_environment;
extern int return_catch_flag, return_catch_value;
extern int last_command_exit_value;
extern int executing_command_builtin;
/* How many `levels' of sourced files we have. */
int sourcelevel = 0;
static int
_evalfile (filename, flags)
const char *filename;
int flags;
{
volatile int old_interactive;
procenv_t old_return_catch;
int return_val, fd, result, pflags, i, nnull;
ssize_t nr; /* return value from read(2) */
char *string;
struct stat finfo;
size_t file_size;
sh_vmsg_func_t *errfunc;
#if defined (ARRAY_VARS)
SHELL_VAR *funcname_v, *nfv, *bash_source_v, *bash_lineno_v;
ARRAY *funcname_a, *bash_source_a, *bash_lineno_a;
# if defined (DEBUGGER)
SHELL_VAR *bash_argv_v, *bash_argc_v;
ARRAY *bash_argv_a, *bash_argc_a;
# endif
char *t, tt[2];
#endif
USE_VAR(pflags);
#if defined (ARRAY_VARS)
GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a);
GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a);
# if defined (DEBUGGER)
GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
# endif
#endif
fd = open (filename, O_RDONLY);
if (fd < 0 || (fstat (fd, &finfo) == -1))
{
file_error_and_exit:
if (((flags & FEVAL_ENOENTOK) == 0) || errno != ENOENT)
file_error (filename);
if (flags & FEVAL_LONGJMP)
{
last_command_exit_value = 1;
jump_to_top_level (EXITPROG);
}
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE
: ((errno == ENOENT) ? 0 : -1));
}
errfunc = ((flags & FEVAL_BUILTIN) ? builtin_error : internal_error);
if (S_ISDIR (finfo.st_mode))
{
(*errfunc) (_("%s: is a directory"), filename);
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1);
}
else if ((flags & FEVAL_REGFILE) && S_ISREG (finfo.st_mode) == 0)
{
(*errfunc) (_("%s: not a regular file"), filename);
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1);
}
file_size = (size_t)finfo.st_size;
/* Check for overflow with large files. */
if (file_size != finfo.st_size || file_size + 1 < file_size)
{
(*errfunc) (_("%s: file is too large"), filename);
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1);
}
if (S_ISREG (finfo.st_mode) && file_size <= SSIZE_MAX)
{
string = (char *)xmalloc (1 + file_size);
nr = read (fd, string, file_size);
if (nr >= 0)
string[nr] = '\0';
}
else
nr = zmapfd (fd, &string, 0);
return_val = errno;
close (fd);
errno = return_val;
if (nr < 0) /* XXX was != file_size, not < 0 */
{
free (string);
goto file_error_and_exit;
}
if (nr == 0)
{
free (string);
return ((flags & FEVAL_BUILTIN) ? EXECUTION_SUCCESS : 1);
}
if ((flags & FEVAL_CHECKBINARY) &&
check_binary_file (string, (nr > 80) ? 80 : nr))
{
free (string);
(*errfunc) (_("%s: cannot execute binary file"), filename);
return ((flags & FEVAL_BUILTIN) ? EX_BINARY_FILE : -1);
}
i = strlen (string);
if (i < nr)
{
for (nnull = i = 0; i < nr; i++)
if (string[i] == '\0')
{
memmove (string+i, string+i+1, nr - i);
nr--;
/* Even if the `check binary' flag is not set, we want to avoid
sourcing files with more than 256 null characters -- that
probably indicates a binary file. */
if ((flags & FEVAL_BUILTIN) && ++nnull > 256)
{
free (string);
(*errfunc) (_("%s: cannot execute binary file"), filename);
return ((flags & FEVAL_BUILTIN) ? EX_BINARY_FILE : -1);
}
}
}
if (flags & FEVAL_UNWINDPROT)
{
begin_unwind_frame ("_evalfile");
unwind_protect_int (return_catch_flag);
unwind_protect_jmp_buf (return_catch);
if (flags & FEVAL_NONINT)
unwind_protect_int (interactive);
unwind_protect_int (sourcelevel);
}
else
{
COPY_PROCENV (return_catch, old_return_catch);
if (flags & FEVAL_NONINT)
old_interactive = interactive;
}
if (flags & FEVAL_NONINT)
interactive = 0;
return_catch_flag++;
sourcelevel++;
#if defined (ARRAY_VARS)
array_push (bash_source_a, (char *)filename);
t = itos (executing_line_number ());
array_push (bash_lineno_a, t);
free (t);
array_push (funcname_a, "source"); /* not exactly right */
# if defined (DEBUGGER)
/* Have to figure out a better way to do this when `source' is supplied
arguments */
if ((flags & FEVAL_NOPUSHARGS) == 0)
{
array_push (bash_argv_a, (char *)filename);
tt[0] = '1'; tt[1] = '\0';
array_push (bash_argc_a, tt);
}
# endif
#endif
/* set the flags to be passed to parse_and_execute */
pflags = SEVAL_RESETLINE;
pflags |= (flags & FEVAL_HISTORY) ? 0 : SEVAL_NOHIST;
if (flags & FEVAL_BUILTIN)
result = EXECUTION_SUCCESS;
return_val = setjmp (return_catch);
/* If `return' was seen outside of a function, but in the script, then
force parse_and_execute () to clean up. */
if (return_val)
{
parse_and_execute_cleanup ();
result = return_catch_value;
}
else
result = parse_and_execute (string, filename, pflags);
if (flags & FEVAL_UNWINDPROT)
run_unwind_frame ("_evalfile");
else
{
if (flags & FEVAL_NONINT)
interactive = old_interactive;
return_catch_flag--;
sourcelevel--;
COPY_PROCENV (old_return_catch, return_catch);
}
#if defined (ARRAY_VARS)
/* These two variables cannot be unset, and cannot be affected by the
sourced file. */
array_pop (bash_source_a);
array_pop (bash_lineno_a);
/* FUNCNAME can be unset, and so can potentially be changed by the
sourced file. */
GET_ARRAY_FROM_VAR ("FUNCNAME", nfv, funcname_a);
if (nfv == funcname_v)
array_pop (funcname_a);
# if defined (DEBUGGER)
if ((flags & FEVAL_NOPUSHARGS) == 0)
{
array_pop (bash_argc_a);
array_pop (bash_argv_a);
}
# endif
#endif
return ((flags & FEVAL_BUILTIN) ? result : 1);
}
int
maybe_execute_file (fname, force_noninteractive)
const char *fname;
int force_noninteractive;
{
char *filename;
int result, flags;
filename = bash_tilde_expand (fname, 0);
flags = FEVAL_ENOENTOK;
if (force_noninteractive)
flags |= FEVAL_NONINT;
result = _evalfile (filename, flags);
free (filename);
return result;
}
#if defined (HISTORY)
int
fc_execute_file (filename)
const char *filename;
{
int flags;
/* We want these commands to show up in the history list if
remember_on_history is set. */
flags = FEVAL_ENOENTOK|FEVAL_HISTORY|FEVAL_REGFILE;
return (_evalfile (filename, flags));
}
#endif /* HISTORY */
int
source_file (filename, sflags)
const char *filename;
int sflags;
{
int flags, rval;
flags = FEVAL_BUILTIN|FEVAL_UNWINDPROT|FEVAL_NONINT;
if (sflags)
flags |= FEVAL_NOPUSHARGS;
/* POSIX shells exit if non-interactive and file error. */
if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
flags |= FEVAL_LONGJMP;
rval = _evalfile (filename, flags);
run_return_trap ();
return rval;
}
+23 -3
View File
@@ -192,6 +192,7 @@ parse_and_execute (string, from_file, flags)
int code, lreset;
volatile int should_jump_to_top_level, last_result;
COMMAND *volatile command;
volatile sigset_t pe_sigmask;
parse_prologue (string, flags, PE_TAG);
@@ -199,6 +200,12 @@ parse_and_execute (string, from_file, flags)
lreset = flags & SEVAL_RESETLINE;
#if defined (HAVE_POSIX_SIGNALS)
/* If we longjmp and are going to go on, use this to restore signal mask */
sigemptyset (&pe_sigmask);
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &pe_sigmask);
#endif
/* Reset the line number if the caller wants us to. If we don't reset the
line number, we have to subtract one, because we will add one just
before executing the next command (resetting the line number sets it to
@@ -226,7 +233,7 @@ parse_and_execute (string, from_file, flags)
/* Provide a location for functions which `longjmp (top_level)' to
jump to. This prevents errors in substitution from restarting
the reader loop directly, for example. */
code = setjmp (top_level);
code = setjmp_nosigs (top_level);
if (code)
{
@@ -269,6 +276,9 @@ parse_and_execute (string, from_file, flags)
{
#if 0
dispose_command (command); /* pe_dispose does this */
#endif
#if defined (HAVE_POSIX_SIGNALS)
sigprocmask (SIG_SETMASK, &pe_sigmask, (sigset_t *)NULL);
#endif
continue;
}
@@ -407,9 +417,16 @@ parse_string (string, from_file, flags, endp)
volatile int should_jump_to_top_level;
COMMAND *volatile command, *oglobal;
char *ostring;
volatile sigset_t ps_sigmask;
parse_prologue (string, flags, PS_TAG);
#if defined (HAVE_POSIX_SIGNALS)
/* If we longjmp and are going to go on, use this to restore signal mask */
sigemptyset (&ps_sigmask);
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &ps_sigmask);
#endif
/* Reset the line number if the caller wants us to. If we don't reset the
line number, we have to subtract one, because we will add one just
before executing the next command (resetting the line number sets it to
@@ -432,7 +449,7 @@ parse_string (string, from_file, flags, endp)
/* Provide a location for functions which `longjmp (top_level)' to
jump to. */
code = setjmp (top_level);
code = setjmp_nosigs (top_level);
if (code)
{
@@ -454,6 +471,9 @@ itrace("parse_string: longjmp executed: code = %d", code);
goto out;
default:
#if defined (HAVE_POSIX_SIGNALS)
sigprocmask (SIG_SETMASK, &ps_sigmask, (sigset_t *)NULL);
#endif
command_error ("parse_string", CMDERR_BADJUMP, code, 0);
break;
}
@@ -558,7 +578,7 @@ evalstring (string, from_file, flags)
unwind_protect_jmp_buf (return_catch);
return_catch_flag++; /* increment so we have a counter */
rcatch = setjmp (return_catch);
rcatch = setjmp_nosigs (return_catch);
}
if (rcatch)
+604
View File
@@ -0,0 +1,604 @@
/* evalstring.c - evaluate a string as one or more shell commands. */
/* Copyright (C) 1996-2012 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include "filecntl.h"
#include "../bashansi.h"
#include "../shell.h"
#include "../jobs.h"
#include "../builtins.h"
#include "../flags.h"
#include "../input.h"
#include "../execute_cmd.h"
#include "../redir.h"
#include "../trap.h"
#include "../bashintl.h"
#include <y.tab.h>
#if defined (HISTORY)
# include "../bashhist.h"
#endif
#include "common.h"
#include "builtext.h"
#if !defined (errno)
extern int errno;
#endif
#define IS_BUILTIN(s) (builtin_address_internal(s, 0) != (struct builtin *)NULL)
extern int indirection_level, subshell_environment;
extern int line_number, line_number_for_err_trap;
extern int current_token, shell_eof_token;
extern int last_command_exit_value;
extern int running_trap;
extern int loop_level;
extern int executing_list;
extern int comsub_ignore_return;
extern int posixly_correct;
extern int return_catch_flag, return_catch_value;
extern sh_builtin_func_t *this_shell_builtin;
extern char *the_printed_command_except_trap;
int parse_and_execute_level = 0;
static int cat_file __P((REDIRECT *));
#define PE_TAG "parse_and_execute top"
#define PS_TAG "parse_string top"
#if defined (HISTORY)
static void
set_history_remembering ()
{
remember_on_history = enable_history_list;
}
#endif
static void
restore_lastcom (x)
char *x;
{
FREE (the_printed_command_except_trap);
the_printed_command_except_trap = x;
}
/* How to force parse_and_execute () to clean up after itself. */
void
parse_and_execute_cleanup ()
{
if (running_trap)
{
run_trap_cleanup (running_trap - 1);
unfreeze_jobs_list ();
}
if (have_unwind_protects ())
run_unwind_frame (PE_TAG);
else
parse_and_execute_level = 0; /* XXX */
}
static void
parse_prologue (string, flags, tag)
char *string;
int flags;
char *tag;
{
char *orig_string, *lastcom;
int x;
orig_string = string;
/* Unwind protect this invocation of parse_and_execute (). */
begin_unwind_frame (tag);
unwind_protect_int (parse_and_execute_level);
unwind_protect_jmp_buf (top_level);
unwind_protect_int (indirection_level);
unwind_protect_int (line_number);
unwind_protect_int (line_number_for_err_trap);
unwind_protect_int (loop_level);
unwind_protect_int (executing_list);
unwind_protect_int (comsub_ignore_return);
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
unwind_protect_int (interactive);
#if defined (HISTORY)
if (parse_and_execute_level == 0)
add_unwind_protect (set_history_remembering, (char *)NULL);
else
unwind_protect_int (remember_on_history); /* can be used in scripts */
# if defined (BANG_HISTORY)
if (interactive_shell)
unwind_protect_int (history_expansion_inhibited);
# endif /* BANG_HISTORY */
#endif /* HISTORY */
if (interactive_shell)
{
x = get_current_prompt_level ();
add_unwind_protect (set_current_prompt_level, x);
}
if (the_printed_command_except_trap)
{
lastcom = savestring (the_printed_command_except_trap);
add_unwind_protect (restore_lastcom, lastcom);
}
add_unwind_protect (pop_stream, (char *)NULL);
if (orig_string && ((flags & SEVAL_NOFREE) == 0))
add_unwind_protect (xfree, orig_string);
end_unwind_frame ();
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
interactive = (flags & SEVAL_NONINT) ? 0 : 1;
#if defined (HISTORY)
if (flags & SEVAL_NOHIST)
bash_history_disable ();
#endif /* HISTORY */
}
/* Parse and execute the commands in STRING. Returns whatever
execute_command () returns. This frees STRING. FLAGS is a
flags word; look in common.h for the possible values. Actions
are:
(flags & SEVAL_NONINT) -> interactive = 0;
(flags & SEVAL_INTERACT) -> interactive = 1;
(flags & SEVAL_NOHIST) -> call bash_history_disable ()
(flags & SEVAL_NOFREE) -> don't free STRING when finished
(flags & SEVAL_RESETLINE) -> reset line_number to 1
*/
int
parse_and_execute (string, from_file, flags)
char *string;
const char *from_file;
int flags;
{
int code, lreset;
volatile int should_jump_to_top_level, last_result;
COMMAND *volatile command;
volatile sigset_t pe_sigmask;
parse_prologue (string, flags, PE_TAG);
parse_and_execute_level++;
lreset = flags & SEVAL_RESETLINE;
#if defined (HAVE_POSIX_SIGNALS)
/* If we longjmp and are going to go on, use this to restore signal mask */
sigemptyset (&pe_sigmask);
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &pe_sigmask);
#endif
/* Reset the line number if the caller wants us to. If we don't reset the
line number, we have to subtract one, because we will add one just
before executing the next command (resetting the line number sets it to
0; the first line number is 1). */
push_stream (lreset);
if (lreset == 0)
line_number--;
indirection_level++;
code = should_jump_to_top_level = 0;
last_result = EXECUTION_SUCCESS;
with_input_from_string (string, from_file);
while (*(bash_input.location.string))
{
command = (COMMAND *)NULL;
if (interrupt_state)
{
last_result = EXECUTION_FAILURE;
break;
}
/* Provide a location for functions which `longjmp (top_level)' to
jump to. This prevents errors in substitution from restarting
the reader loop directly, for example. */
code = setjmp_nosigs (top_level);
if (code)
{
should_jump_to_top_level = 0;
switch (code)
{
case ERREXIT:
/* variable_context -> 0 is what eval.c:reader_loop() does in
these circumstances. Don't bother with cleanup here because
we don't want to run the function execution cleanup stuff
that will cause pop_context and other functions to run.
XXX - change that if we want the function context to be
unwound. */
if (exit_immediately_on_error && variable_context)
{
discard_unwind_frame ("pe_dispose");
variable_context = 0; /* not in a function */
}
should_jump_to_top_level = 1;
goto out;
case FORCE_EOF:
case EXITPROG:
if (command)
run_unwind_frame ("pe_dispose");
/* Remember to call longjmp (top_level) after the old
value for it is restored. */
should_jump_to_top_level = 1;
goto out;
case DISCARD:
if (command)
run_unwind_frame ("pe_dispose");
last_result = last_command_exit_value = EXECUTION_FAILURE; /* XXX */
if (subshell_environment)
{
should_jump_to_top_level = 1;
goto out;
}
else
{
#if 0
dispose_command (command); /* pe_dispose does this */
#endif
#if defined (HAVE_POSIX_SIGNALS)
sigprocmask (SIG_SETMASK, &pe_sigmask, (sigset_t *)NULL);
#endif
continue;
}
default:
command_error ("parse_and_execute", CMDERR_BADJUMP, code, 0);
break;
}
}
if (parse_command () == 0)
{
if ((flags & SEVAL_PARSEONLY) || (interactive_shell == 0 && read_but_dont_execute))
{
last_result = EXECUTION_SUCCESS;
dispose_command (global_command);
global_command = (COMMAND *)NULL;
}
else if (command = global_command)
{
struct fd_bitmap *bitmap;
bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
begin_unwind_frame ("pe_dispose");
add_unwind_protect (dispose_fd_bitmap, bitmap);
add_unwind_protect (dispose_command, command); /* XXX */
global_command = (COMMAND *)NULL;
if ((subshell_environment & SUBSHELL_COMSUB) && comsub_ignore_return)
command->flags |= CMD_IGNORE_RETURN;
#if defined (ONESHOT)
/*
* IF
* we were invoked as `bash -c' (startup_state == 2) AND
* parse_and_execute has not been called recursively AND
* we're not running a trap AND
* we have parsed the full command (string == '\0') AND
* we're not going to run the exit trap AND
* we have a simple command without redirections AND
* the command is not being timed AND
* the command's return status is not being inverted
* THEN
* tell the execution code that we don't need to fork
*/
if (startup_state == 2 && parse_and_execute_level == 1 &&
running_trap == 0 &&
*bash_input.location.string == '\0' &&
command->type == cm_simple &&
signal_is_trapped (EXIT_TRAP) == 0 &&
command->redirects == 0 && command->value.Simple->redirects == 0 &&
((command->flags & CMD_TIME_PIPELINE) == 0) &&
((command->flags & CMD_INVERT_RETURN) == 0))
{
command->flags |= CMD_NO_FORK;
command->value.Simple->flags |= CMD_NO_FORK;
}
#endif /* ONESHOT */
/* See if this is a candidate for $( <file ). */
if (startup_state == 2 &&
(subshell_environment & SUBSHELL_COMSUB) &&
*bash_input.location.string == '\0' &&
command->type == cm_simple && !command->redirects &&
(command->flags & CMD_TIME_PIPELINE) == 0 &&
command->value.Simple->words == 0 &&
command->value.Simple->redirects &&
command->value.Simple->redirects->next == 0 &&
command->value.Simple->redirects->instruction == r_input_direction &&
command->value.Simple->redirects->redirector.dest == 0)
{
int r;
r = cat_file (command->value.Simple->redirects);
last_result = (r < 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
}
else
last_result = execute_command_internal
(command, 0, NO_PIPE, NO_PIPE, bitmap);
dispose_command (command);
dispose_fd_bitmap (bitmap);
discard_unwind_frame ("pe_dispose");
}
}
else
{
last_result = EXECUTION_FAILURE;
if (interactive_shell == 0 && this_shell_builtin &&
(this_shell_builtin == source_builtin || this_shell_builtin == eval_builtin) &&
last_command_exit_value == EX_BADSYNTAX && posixly_correct)
{
should_jump_to_top_level = 1;
code = ERREXIT;
last_command_exit_value = EX_BADUSAGE;
}
/* Since we are shell compatible, syntax errors in a script
abort the execution of the script. Right? */
break;
}
}
out:
run_unwind_frame (PE_TAG);
if (interrupt_state && parse_and_execute_level == 0)
{
/* An interrupt during non-interactive execution in an
interactive shell (e.g. via $PROMPT_COMMAND) should
not cause the shell to exit. */
interactive = interactive_shell;
throw_to_top_level ();
}
if (should_jump_to_top_level)
jump_to_top_level (code);
return (last_result);
}
/* Parse a command contained in STRING according to FLAGS and return the
number of characters consumed from the string. If non-NULL, set *ENDP
to the position in the string where the parse ended. Used to validate
command substitutions during parsing to obey Posix rules about finding
the end of the command and balancing parens. */
int
parse_string (string, from_file, flags, endp)
char *string;
const char *from_file;
int flags;
char **endp;
{
int code, nc;
volatile int should_jump_to_top_level;
COMMAND *volatile command, *oglobal;
char *ostring;
volatile sigset_t ps_sigmask;
parse_prologue (string, flags, PS_TAG);
#if defined (HAVE_POSIX_SIGNALS)
/* If we longjmp and are going to go on, use this to restore signal mask */
sigemptyset (&ps_sigmask);
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &ps_sigmask);
#endif
/* Reset the line number if the caller wants us to. If we don't reset the
line number, we have to subtract one, because we will add one just
before executing the next command (resetting the line number sets it to
0; the first line number is 1). */
push_stream (0);
code = should_jump_to_top_level = 0;
oglobal = global_command;
ostring = string;
with_input_from_string (string, from_file);
while (*(bash_input.location.string))
{
command = (COMMAND *)NULL;
#if 0
if (interrupt_state)
break;
#endif
/* Provide a location for functions which `longjmp (top_level)' to
jump to. */
code = setjmp_nosigs (top_level);
if (code)
{
#if defined (DEBUG)
itrace("parse_string: longjmp executed: code = %d", code);
#endif
should_jump_to_top_level = 0;
switch (code)
{
case FORCE_EOF:
case ERREXIT:
case EXITPROG:
case DISCARD: /* XXX */
if (command)
dispose_command (command);
/* Remember to call longjmp (top_level) after the old
value for it is restored. */
should_jump_to_top_level = 1;
goto out;
default:
#if defined (HAVE_POSIX_SIGNALS)
sigprocmask (SIG_SETMASK, &ps_sigmask, (sigset_t *)NULL);
#endif
command_error ("parse_string", CMDERR_BADJUMP, code, 0);
break;
}
}
if (parse_command () == 0)
{
dispose_command (global_command);
global_command = (COMMAND *)NULL;
}
else
{
if ((flags & SEVAL_NOLONGJMP) == 0)
{
should_jump_to_top_level = 1;
code = DISCARD;
}
else
reset_parser (); /* XXX - sets token_to_read */
break;
}
if (current_token == yacc_EOF || current_token == shell_eof_token)
break;
}
out:
global_command = oglobal;
nc = bash_input.location.string - ostring;
if (endp)
*endp = bash_input.location.string;
run_unwind_frame (PS_TAG);
if (should_jump_to_top_level)
jump_to_top_level (code);
return (nc);
}
/* Handle a $( < file ) command substitution. This expands the filename,
returning errors as appropriate, then just cats the file to the standard
output. */
static int
cat_file (r)
REDIRECT *r;
{
char *fn;
int fd, rval;
if (r->instruction != r_input_direction)
return -1;
/* Get the filename. */
if (posixly_correct && !interactive_shell)
disallow_filename_globbing++;
fn = redirection_expand (r->redirectee.filename);
if (posixly_correct && !interactive_shell)
disallow_filename_globbing--;
if (fn == 0)
{
redirection_error (r, AMBIGUOUS_REDIRECT);
return -1;
}
fd = open(fn, O_RDONLY);
if (fd < 0)
{
file_error (fn);
free (fn);
return -1;
}
rval = zcatfd (fd, 1, fn);
free (fn);
close (fd);
return (rval);
}
int
evalstring (string, from_file, flags)
char *string;
const char *from_file;
int flags;
{
volatile int r, rflag, rcatch;
rcatch = 0;
rflag = return_catch_flag;
/* If we are in a place where `return' is valid, we have to catch
`eval "... return"' and make sure parse_and_execute cleans up. Then
we can trampoline to the previous saved return_catch location. */
if (rflag)
{
begin_unwind_frame ("evalstring");
unwind_protect_int (return_catch_flag);
unwind_protect_jmp_buf (return_catch);
return_catch_flag++; /* increment so we have a counter */
rcatch = setjmp_nosigs (return_catch);
}
if (rcatch)
{
parse_and_execute_cleanup ();
r = return_catch_value;
}
else
/* Note that parse_and_execute () frees the string it is passed. */
r = parse_and_execute (string, from_file, flags);
if (rflag)
{
run_unwind_frame ("evalstring");
if (rcatch && return_catch_flag)
{
return_catch_value = r;
longjmp (return_catch, 1);
}
}
return (r);
}
+1 -1
View File
@@ -404,7 +404,7 @@ read_builtin (list)
if (tmsec > 0 || tmusec > 0)
{
code = setjmp (alrmbuf);
code = setjmp_nosigs (alrmbuf);
if (code)
{
sigalrm_seen = 0;
+8 -2
View File
@@ -416,6 +416,7 @@ read_builtin (list)
remove_unwind_protect ();
run_unwind_frame ("read_builtin");
input_string[i] = '\0'; /* make sure it's terminated */
itrace("SIGALRM seen: input_string = '%s'", input_string);
retval = 128+SIGALRM;
goto assign_vars;
}
@@ -483,7 +484,10 @@ read_builtin (list)
add_unwind_protect (xfree, input_string);
CHECK_ALRM;
unbuffered_read = (nchars > 0) || (delim != '\n') || input_is_pipe;
if ((nchars > 0) && (input_is_tty == 0) && ignore_delim) /* read -N */
unbuffered_read = 2;
else if ((nchars > 0) || (delim != '\n') || input_is_pipe)
unbuffered_read = 1;
if (prompt && edit == 0)
{
@@ -540,7 +544,9 @@ read_builtin (list)
interrupt_immediately++;
#endif
reading = 1;
if (unbuffered_read)
if (unbuffered_read == 2)
retval = posixly_correct ? zreadintr (fd, &c, 1) : zreadn (fd, &c, nchars - nr);
else if (unbuffered_read)
retval = posixly_correct ? zreadintr (fd, &c, 1) : zread (fd, &c, 1);
else
retval = posixly_correct ? zreadcintr (fd, &c) : zreadc (fd, &c);