commit bash-20140926 snapshot

This commit is contained in:
Chet Ramey
2014-10-09 20:24:28 -04:00
parent d402782426
commit 30595b57d9
36 changed files with 28423 additions and 1125 deletions
+55 -1
View File
@@ -6795,4 +6795,58 @@ variables.c
builtins/evalstring.c
- parse_and_execute: if SEVAL_ONECMD flag set, return immediately after
calling execute_command_internal. Final piece for fix for bug
reported by Stephane Chazelas <stephane.chazelas@gmail.com>
reported by Stephane Chazelas <stephane.chazelas@gmail.com>. Part of
CVE-2014-6271
9/24
----
parse.y
- reset_parser: reset eol_ungetc_lookahead to 0 here, since we don't want
shell_getc returning it on the next call. Fixes problem reported by
Tavis Ormandy <taviso@cmpxchg8b.com> and Michal Zalewski
<lcamtuf@coredump.cx>. Potentially part of CVE-2014-6271; fix for
CVE-2014-7169
9/25
----
parse.y
- push_heredoc: new function, pushes a here-doc redirection onto
redir_stack handling overflow of redir_stack. Exits on overflow.
Original fix from Florian Weimer <fweimer@redhat.com>
- change straight assignments to redir_stack to call push_redir
- add one to size of word_lineno stack to avoid off-by-one error
below in read_token_word. Overflow just results in line numbers
being wrong
9/27
----
{execute_cmd,trap}.c
- changes to make minimal-config builds work again, mostly missing
#ifdefs for optional features
builtins/common.c
- builtin_help: dummy version to be included if HELP_BUILTIN not
defined, for minimal-config builds
variables.c
- initialize_shell_variables: incorporated patches from Florian
Weimer <fweimer@redhat.com> to change the strings bash looks
for when importing shell functions from the environment. It
adds a prefix (BASH_FUNC_) and a suffix (%%) to the name to
mark it as having been created by bash as an exported function.
Fix for remote attacks part of CVE-2014-6271 and CVE-2014-7169
- mk_env_string: takes new argument, indicating whether we are
constructing a function
- mk_env_string: encodes function names as described above, so
initialize_shell_variables can find them
9/28
----
copy_cmd.c
- copy_redirects: before calling savestring on here_doc_eof, make
sure it's not NULL (it could have been the result of a here
document delimited by EOF or EOS). Fixes bug reported by
Michal Zalewski <lcamtuf@coredump.cx>.
make_cmd.c
- make_redirection: initialize here_doc_eof member to NULL
+6849
View File
File diff suppressed because it is too large Load Diff
+82
View File
@@ -0,0 +1,82 @@
Starting bash with the `--posix' command-line option or executing
`set -o posix' while bash is running will cause bash to conform more
closely to the Posix.2 standard by changing the behavior to match that
specified by Posix.2 in areas where the bash default differs.
The following list is what's changed when `posix mode' is in effect:
1. When a command in the hash table no longer exists, bash will re-search
$PATH to find the new location. This is also available with
`shopt -s checkhash'.
2. The >& redirection does not redirect stdout and stderr.
3. The message printed by the job control code and builtins when a job
exits with a non-zero status is `Done(status)'.
4. Reserved words may not be aliased.
5. The Posix.2 PS1 and PS2 expansions of `!' -> history number and
`!!' -> `!' are enabled, and parameter expansion is performed on
the value regardless of the setting of the `promptvars' option.
6. Interactive comments are enabled by default. (Note that bash has
them on by default anyway.)
7. The Posix.2 startup files are executed ($ENV) rather than the normal
bash files.
8. Tilde expansion is only performed on assignments preceding a command
name, rather than on all assignment statements on the line.
9. The default history file is ~/.sh_history (default value of $HISTFILE).
10. The output of `kill -l' prints all the signal names on a single line,
separated by spaces.
11. Non-interactive shells exit if `file' in `. file' is not found.
12. Redirection operators do not perform pathname expansion on the word
in the redirection unless the shell is interactive
13. Function names must be valid shell identifiers. That is, they may not
contain characters other than letters, digits, and underscores, and
may not start with a digit. Declaring a function with an illegal name
causes a fatal syntax error in non-interactive shells.
14. Posix.2 `special' builtins are found before shell functions during command
lookup.
15. If a Posix.2 special builtin returns an error status, a non-interactive
shell exits. The fatal errors are those listed in the POSIX.2 standard,
and include things like passing incorrect options, redirection errors,
variable assignment errors for assignments preceding the command name,
and so on.
16. The environment passed to executed commands is not sorted. Neither is
the output of `set'. This is not strictly Posix.2 behavior, but sh
does it this way. Ksh does not. It's not necessary to sort the
environment; no program should rely on it being sorted.
17. If the `cd' builtin finds a directory to change to using $CDPATH, the
value it assigns to $PWD does not contain any symbolic links, as if
`cd -P' had been executed.
18. A non-interactive shell exits with an error status if a variable
assignment error occurs when no command name follows the assignment
statements. A variable assignment error occurs, for example, when
trying to assign a value to a read-only variable.
19. A non-interactive shell exits with an error status if the iteration
variable in a for statement or the selection variable in a select
statement is a read-only variable.
20. Process substitution is not available.
21. Assignment statements preceding POSIX.2 `special' builtins persist in
the shell environment after the builtin completes.
There is other Posix.2 behavior that bash does not implement. Specifically:
1. Assignment statements affect the execution environment of all builtins,
not just special ones.
+544
View File
@@ -0,0 +1,544 @@
This file is set.def, from which is created set.c.
It implements the "set" and "unset" builtins in Bash.
Copyright (C) 1987, 1989, 1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
$PRODUCES set.c
#include <stdio.h>
#include "../shell.h"
#include "../flags.h"
#include "bashgetopt.h"
extern int interactive;
extern int noclobber, posixly_correct;
#if defined (READLINE)
extern int rl_editing_mode, no_line_editing;
#endif /* READLINE */
$BUILTIN set
$FUNCTION set_builtin
$SHORT_DOC set [--abefhkmnptuvxldBCHP] [-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 Locate and remember function commands as functions are
defined. Function commands are normally looked up when
the function is executed.
-i Force the shell to be an "interactive" one. Interactive shells
always read `~/.bashrc' on startup.
-k All keyword 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
histexpand same as -H
ignoreeof the shell will not exit upon reading EOF
interactive-comments
allow comments to appear in interactive commands
monitor same as -m
noclobber disallow redirection to existing files
noexec same as -n
noglob same as -f
nohash same as -d
notify save as -b
nounset same as -u
physical same as -P
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.
-l Save and restore the binding of the NAME in a FOR command.
-d Disable the hashing of commands that are looked up for execution.
Normally, commands are remembered in a hash table, and once
found, do not have to be looked up again.
#if defined (BRACE_EXPANSION)
-B the shell will perform brace expansion
#endif /* BRACE_EXPANSION */
#if defined (BANG_HISTORY)
-H Enable ! style history substitution. This flag is on
by default.
#endif /* BANG_HISTORY */
-C If set, disallow existing regular files to be overwritten
by redirection of output.
-P If set, do not follow symbolic links when executing commands
such as cd which change the current directory.
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
/* An a-list used to match long options for set -o to the corresponding
option letter. */
struct {
char *name;
int letter;
} o_options[] = {
{ "allexport", 'a' },
#if defined (BRACE_EXPANSION)
{ "braceexpand",'B' },
#endif
{ "errexit", 'e' },
{ "histexpand", 'H' },
{ "monitor", 'm' },
{ "noexec", 'n' },
{ "noglob", 'f' },
{ "nohash", 'd' },
#if defined (JOB_CONTROL)
{ "notify", 'b' },
#endif /* JOB_CONTROL */
{"nounset", 'u' },
{"physical", 'P' },
{"privileged", 'p' },
{"verbose", 'v' },
{"xtrace", 'x' },
{(char *)NULL, 0},
};
#define MINUS_O_FORMAT "%-15s\t%s\n"
void
list_minus_o_opts ()
{
register int i;
char *on = "on", *off = "off";
printf (MINUS_O_FORMAT, "noclobber", (noclobber == 1) ? on : off);
if (find_variable ("ignoreeof") || find_variable ("IGNOREEOF"))
printf (MINUS_O_FORMAT, "ignoreeof", on);
else
printf (MINUS_O_FORMAT, "ignoreeof", off);
printf (MINUS_O_FORMAT, "interactive-comments",
interactive_comments ? on : off);
printf (MINUS_O_FORMAT, "posix", posixly_correct ? on : off);
#if defined (READLINE)
if (no_line_editing)
{
printf (MINUS_O_FORMAT, "emacs", off);
printf (MINUS_O_FORMAT, "vi", off);
}
else
{
/* Magic. This code `knows' how readline handles rl_editing_mode. */
printf (MINUS_O_FORMAT, "emacs", (rl_editing_mode == 1) ? on : off);
printf (MINUS_O_FORMAT, "vi", (rl_editing_mode == 0) ? on : off);
}
#endif /* READLINE */
for (i = 0; o_options[i].name; i++)
{
int *on_or_off, zero = 0;
on_or_off = find_flag (o_options[i].letter);
if (on_or_off == FLAG_UNKNOWN)
on_or_off = &zero;
printf (MINUS_O_FORMAT, o_options[i].name, (*on_or_off == 1) ? on : off);
}
}
set_minus_o_option (on_or_off, option_name)
int on_or_off;
char *option_name;
{
int option_char = -1;
if (STREQ (option_name, "noclobber"))
{
if (on_or_off == FLAG_ON)
bind_variable ("noclobber", "");
else
unbind_variable ("noclobber");
stupidly_hack_special_variables ("noclobber");
}
else if (STREQ (option_name, "ignoreeof"))
{
unbind_variable ("ignoreeof");
unbind_variable ("IGNOREEOF");
if (on_or_off == FLAG_ON)
bind_variable ("IGNOREEOF", "10");
stupidly_hack_special_variables ("IGNOREEOF");
}
#if defined (READLINE)
else if ((STREQ (option_name, "emacs")) || (STREQ (option_name, "vi")))
{
if (on_or_off == FLAG_ON)
{
rl_variable_bind ("editing-mode", option_name);
if (interactive)
with_input_from_stdin ();
no_line_editing = 0;
}
else
{
int isemacs = (rl_editing_mode == 1);
if ((isemacs && STREQ (option_name, "emacs")) ||
(!isemacs && STREQ (option_name, "vi")))
{
if (interactive)
with_input_from_stream (stdin, "stdin");
no_line_editing = 1;
}
else
builtin_error ("not in %s editing mode", option_name);
}
}
#endif /* READLINE */
else if (STREQ (option_name, "interactive-comments"))
interactive_comments = (on_or_off == FLAG_ON);
else if (STREQ (option_name, "posix"))
{
posixly_correct = (on_or_off == FLAG_ON);
unbind_variable ("POSIXLY_CORRECT");
unbind_variable ("POSIX_PEDANTIC");
if (on_or_off == FLAG_ON)
{
bind_variable ("POSIXLY_CORRECT", "");
stupidly_hack_special_variables ("POSIXLY_CORRECT");
}
}
else
{
register int i;
for (i = 0; o_options[i].name; i++)
{
if (STREQ (option_name, o_options[i].name))
{
option_char = o_options[i].letter;
break;
}
}
if (option_char == -1)
{
builtin_error ("%s: unknown option name", option_name);
return (EXECUTION_FAILURE);
}
if (change_flag (option_char, on_or_off) == FLAG_ERROR)
{
bad_option (option_name);
return (EXECUTION_FAILURE);
}
}
return (EXECUTION_SUCCESS);
}
/* 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. */
set_builtin (list)
WORD_LIST *list;
{
int on_or_off, flag_name, force_assignment = 0;
if (!list)
{
SHELL_VAR **vars;
vars = all_shell_variables ();
if (vars)
{
print_var_list (vars);
free (vars);
}
vars = all_shell_functions ();
if (vars)
{
print_var_list (vars);
free (vars);
}
return (EXECUTION_SUCCESS);
}
/* Check validity of flag arguments. */
if (*list->word->word == '-' || *list->word->word == '+')
{
register char *arg;
WORD_LIST *save_list = list;
while (list && (arg = list->word->word))
{
char c;
if (arg[0] != '-' && arg[0] != '+')
break;
/* `-' or `--' signifies end of flag arguments. */
if (arg[0] == '-' &&
(!arg[1] || (arg[1] == '-' && !arg[2])))
break;
while (c = *++arg)
{
if (find_flag (c) == FLAG_UNKNOWN && c != 'o')
{
char s[2];
s[0] = c; s[1] = '\0';
bad_option (s);
if (c == '?')
builtin_usage ();
return (c == '?' ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}
}
list = list->next;
}
list = save_list;
}
/* Do the set command. While the list consists of words starting with
'-' or '+' treat them as flags, otherwise, start assigning them to
$1 ... $n. */
while (list)
{
char *string = list->word->word;
/* If the argument is `--' or `-' then signal the end of the list
and remember the remaining arguments. */
if (string[0] == '-' && (!string[1] || (string[1] == '-' && !string[2])))
{
list = list->next;
/* `set --' unsets the positional parameters. */
if (string[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', '+');
}
break;
}
if ((on_or_off = *string) &&
(on_or_off == '-' || on_or_off == '+'))
{
int i = 1;
while (flag_name = string[i++])
{
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)
{
list_minus_o_opts ();
continue;
}
option_name = opt->word->word;
if (!option_name || !*option_name || (*option_name == '-'))
{
list_minus_o_opts ();
continue;
}
list = list->next; /* Skip over option name. */
if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS)
return (EXECUTION_FAILURE);
}
else
{
if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
{
char opt[3];
opt[0] = on_or_off;
opt[1] = flag_name;
opt[2] = '\0';
bad_option (opt);
builtin_usage ();
return (EXECUTION_FAILURE);
}
}
}
}
else
{
break;
}
list = list->next;
}
/* Assigning $1 ... $n */
if (list || force_assignment)
remember_args (list, 1);
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 (such as PATH and IFS) cannot be unset; also
see readonly.
$END
#define NEXT_VARIABLE() any_failed++; list = list->next; continue;
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 (EXECUTION_FAILURE);
}
}
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)
if (!unset_function && valid_array_reference (name))
{
t = strchr (name, '[');
*t++ = '\0';
unset_array++;
}
#endif
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);
}
else
#endif /* ARRAY_VARS */
tem = makunbound (name, unset_function ? shell_functions : shell_variables);
/* 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 = makunbound (name, shell_functions);
if (tem == -1)
any_failed++;
else if (!unset_function)
stupidly_hack_special_variables (name);
list = list->next;
}
if (any_failed)
return (EXECUTION_FAILURE);
else
return (EXECUTION_SUCCESS);
}
+50
View File
@@ -0,0 +1,50 @@
/* unwind_prot.h - Macros and functions for hacking unwind protection. */
/* Copyright (C) 1993 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
#if !defined (_UNWIND_PROT_H)
#define _UNWIND_PROT_H
/* Run a function without interrupts. */
extern void begin_unwind_frame ();
extern void discard_unwind_frame ();
extern void run_unwind_frame ();
extern void add_unwind_protect ();
extern void remove_unwind_protect ();
extern void run_unwind_protects ();
extern void unwind_protect_var ();
/* Define for people who like their code to look a certain way. */
#define end_unwind_frame()
/* How to protect an integer. */
#define unwind_protect_int(X) unwind_protect_var (&(X), (char *)(X), sizeof (int))
/* How to protect a pointer to a string. */
#define unwind_protect_string(X) \
unwind_protect_var ((int *)&(X), (X), sizeof (char *))
/* How to protect any old pointer. */
#define unwind_protect_pointer(X) unwind_protect_string (X)
/* How to protect the contents of a jmp_buf. */
#define unwind_protect_jmp_buf(X) \
unwind_protect_var ((int *)(X), (char *)(X), sizeof (procenv_t))
#endif /* _UNWIND_PROT_H */
+8
View File
@@ -906,3 +906,11 @@ initialize_shell_builtins ()
qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin),
(QSFUNC *)shell_builtin_compare);
}
#if !defined (HELP_BUILTIN)
void
builtin_help ()
{
printf ("%s: %s\n", this_command_name, _("help not available in this version"));
}
#endif
+908
View File
@@ -0,0 +1,908 @@
/* common.c - utility functions for all builtins */
/* Copyright (C) 1987-2010 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 <chartypes.h>
#include "../bashtypes.h"
#include "posixstat.h"
#include <signal.h>
#include <errno.h>
#if defined (PREFER_STDARG)
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#include "../bashansi.h"
#include "../bashintl.h"
#define NEED_FPURGE_DECL
#include "../shell.h"
#include "maxpath.h"
#include "../flags.h"
#include "../jobs.h"
#include "../builtins.h"
#include "../input.h"
#include "../execute_cmd.h"
#include "../trap.h"
#include "bashgetopt.h"
#include "common.h"
#include "builtext.h"
#include <tilde/tilde.h>
#if defined (HISTORY)
# include "../bashhist.h"
#endif
#if !defined (errno)
extern int errno;
#endif /* !errno */
extern int indirection_level, subshell_environment;
extern int line_number;
extern int last_command_exit_value;
extern int trap_saved_exit_value;
extern int running_trap;
extern int posixly_correct;
extern char *this_command_name, *shell_name;
extern const char * const bash_getcwd_errstr;
/* Used by some builtins and the mainline code. */
sh_builtin_func_t *last_shell_builtin = (sh_builtin_func_t *)NULL;
sh_builtin_func_t *this_shell_builtin = (sh_builtin_func_t *)NULL;
/* **************************************************************** */
/* */
/* Error reporting, usage, and option processing */
/* */
/* **************************************************************** */
/* This is a lot like report_error (), but it is for shell builtins
instead of shell control structures, and it won't ever exit the
shell. */
static void
builtin_error_prolog ()
{
char *name;
name = get_name_for_error ();
fprintf (stderr, "%s: ", name);
if (interactive_shell == 0)
fprintf (stderr, _("line %d: "), executing_line_number ());
if (this_command_name && *this_command_name)
fprintf (stderr, "%s: ", this_command_name);
}
void
#if defined (PREFER_STDARG)
builtin_error (const char *format, ...)
#else
builtin_error (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
builtin_error_prolog ();
SH_VA_START (args, format);
vfprintf (stderr, format, args);
va_end (args);
fprintf (stderr, "\n");
}
void
#if defined (PREFER_STDARG)
builtin_warning (const char *format, ...)
#else
builtin_warning (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
builtin_error_prolog ();
fprintf (stderr, _("warning: "));
SH_VA_START (args, format);
vfprintf (stderr, format, args);
va_end (args);
fprintf (stderr, "\n");
}
/* Print a usage summary for the currently-executing builtin command. */
void
builtin_usage ()
{
if (this_command_name && *this_command_name)
fprintf (stderr, _("%s: usage: "), this_command_name);
fprintf (stderr, "%s\n", _(current_builtin->short_doc));
fflush (stderr);
}
/* Return if LIST is NULL else barf and jump to top_level. Used by some
builtins that do not accept arguments. */
void
no_args (list)
WORD_LIST *list;
{
if (list)
{
builtin_error (_("too many arguments"));
top_level_cleanup ();
jump_to_top_level (DISCARD);
}
}
/* Check that no options were given to the currently-executing builtin,
and return 0 if there were options. */
int
no_options (list)
WORD_LIST *list;
{
int opt;
reset_internal_getopt ();
if ((opt = internal_getopt (list, "")) != -1)
{
if (opt == GETOPT_HELP)
{
builtin_help ();
return (2);
}
builtin_usage ();
return (1);
}
return (0);
}
void
sh_needarg (s)
char *s;
{
builtin_error (_("%s: option requires an argument"), s);
}
void
sh_neednumarg (s)
char *s;
{
builtin_error (_("%s: numeric argument required"), s);
}
void
sh_notfound (s)
char *s;
{
builtin_error (_("%s: not found"), s);
}
/* Function called when one of the builtin commands detects an invalid
option. */
void
sh_invalidopt (s)
char *s;
{
builtin_error (_("%s: invalid option"), s);
}
void
sh_invalidoptname (s)
char *s;
{
builtin_error (_("%s: invalid option name"), s);
}
void
sh_invalidid (s)
char *s;
{
builtin_error (_("`%s': not a valid identifier"), s);
}
void
sh_invalidnum (s)
char *s;
{
char *msg;
if (*s == '0' && isdigit (s[1]))
msg = _("invalid octal number");
else if (*s == '0' && s[1] == 'x')
msg = _("invalid hex number");
else
msg = _("invalid number");
builtin_error ("%s: %s", s, msg);
}
void
sh_invalidsig (s)
char *s;
{
builtin_error (_("%s: invalid signal specification"), s);
}
void
sh_badpid (s)
char *s;
{
builtin_error (_("`%s': not a pid or valid job spec"), s);
}
void
sh_readonly (s)
const char *s;
{
builtin_error (_("%s: readonly variable"), s);
}
void
sh_erange (s, desc)
char *s, *desc;
{
if (s)
builtin_error (_("%s: %s out of range"), s, desc ? desc : _("argument"));
else
builtin_error (_("%s out of range"), desc ? desc : _("argument"));
}
#if defined (JOB_CONTROL)
void
sh_badjob (s)
char *s;
{
builtin_error (_("%s: no such job"), s);
}
void
sh_nojobs (s)
char *s;
{
if (s)
builtin_error (_("%s: no job control"), s);
else
builtin_error (_("no job control"));
}
#endif
#if defined (RESTRICTED_SHELL)
void
sh_restricted (s)
char *s;
{
if (s)
builtin_error (_("%s: restricted"), s);
else
builtin_error (_("restricted"));
}
#endif
void
sh_notbuiltin (s)
char *s;
{
builtin_error (_("%s: not a shell builtin"), s);
}
void
sh_wrerror ()
{
#if defined (DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS) && defined (EPIPE)
if (errno != EPIPE)
#endif /* DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS && EPIPE */
builtin_error (_("write error: %s"), strerror (errno));
}
void
sh_ttyerror (set)
int set;
{
if (set)
builtin_error (_("error setting terminal attributes: %s"), strerror (errno));
else
builtin_error (_("error getting terminal attributes: %s"), strerror (errno));
}
int
sh_chkwrite (s)
int s;
{
fflush (stdout);
if (ferror (stdout))
{
sh_wrerror ();
fpurge (stdout);
clearerr (stdout);
return (EXECUTION_FAILURE);
}
return (s);
}
/* **************************************************************** */
/* */
/* Shell positional parameter manipulation */
/* */
/* **************************************************************** */
/* Convert a WORD_LIST into a C-style argv. Return the number of elements
in the list in *IP, if IP is non-null. A convenience function for
loadable builtins; also used by `test'. */
char **
make_builtin_argv (list, ip)
WORD_LIST *list;
int *ip;
{
char **argv;
argv = strvec_from_word_list (list, 0, 1, ip);
argv[0] = this_command_name;
return argv;
}
/* Remember LIST in $1 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is
non-zero, then discard whatever the existing arguments are, else
only discard the ones that are to be replaced. */
void
remember_args (list, destructive)
WORD_LIST *list;
int destructive;
{
register int i;
for (i = 1; i < 10; i++)
{
if ((destructive || list) && dollar_vars[i])
{
free (dollar_vars[i]);
dollar_vars[i] = (char *)NULL;
}
if (list)
{
dollar_vars[i] = savestring (list->word->word);
list = list->next;
}
}
/* If arguments remain, assign them to REST_OF_ARGS.
Note that copy_word_list (NULL) returns NULL, and
that dispose_words (NULL) does nothing. */
if (destructive || list)
{
dispose_words (rest_of_args);
rest_of_args = copy_word_list (list);
}
if (destructive)
set_dollar_vars_changed ();
}
static int changed_dollar_vars;
/* Have the dollar variables been reset to new values since we last
checked? */
int
dollar_vars_changed ()
{
return (changed_dollar_vars);
}
void
set_dollar_vars_unchanged ()
{
changed_dollar_vars = 0;
}
void
set_dollar_vars_changed ()
{
if (variable_context)
changed_dollar_vars |= ARGS_FUNC;
else if (this_shell_builtin == set_builtin)
changed_dollar_vars |= ARGS_SETBLTIN;
else
changed_dollar_vars |= ARGS_INVOC;
}
/* **************************************************************** */
/* */
/* Validating numeric input and arguments */
/* */
/* **************************************************************** */
/* Read a numeric arg for this_command_name, the name of the shell builtin
that wants it. LIST is the word list that the arg is to come from.
Accept only the numeric argument; report an error if other arguments
follow. If FATAL is 1, call throw_to_top_level, which exits the
shell; if it's 2, call jump_to_top_level (DISCARD), which aborts the
current command; if FATAL is 0, return an indication of an invalid
number by setting *NUMOK == 0 and return -1. */
int
get_numeric_arg (list, fatal, count)
WORD_LIST *list;
int fatal;
intmax_t *count;
{
char *arg;
if (count)
*count = 1;
if (list && list->word && ISOPTION (list->word->word, '-'))
list = list->next;
if (list)
{
arg = list->word->word;
if (arg == 0 || (legal_number (arg, count) == 0))
{
sh_neednumarg (list->word->word ? list->word->word : "`'");
if (fatal == 0)
return 0;
else if (fatal == 1) /* fatal == 1; abort */
throw_to_top_level ();
else /* fatal == 2; discard current command */
{
top_level_cleanup ();
jump_to_top_level (DISCARD);
}
}
no_args (list->next);
}
return (1);
}
/* Get an eight-bit status value from LIST */
int
get_exitstat (list)
WORD_LIST *list;
{
int status;
intmax_t sval;
char *arg;
if (list && list->word && ISOPTION (list->word->word, '-'))
list = list->next;
if (list == 0)
{
/* If we're not running the DEBUG trap, the return builtin, when not
given any arguments, uses the value of $? before the trap ran. If
given an argument, return uses it. This means that the trap can't
change $?. The DEBUG trap gets to change $?, though, since that is
part of its reason for existing, and because the extended debug mode
does things with the return value. */
if (this_shell_builtin == return_builtin && running_trap > 0 && running_trap != DEBUG_TRAP+1)
return (trap_saved_exit_value);
return (last_command_exit_value);
}
arg = list->word->word;
if (arg == 0 || legal_number (arg, &sval) == 0)
{
sh_neednumarg (list->word->word ? list->word->word : "`'");
return EX_BADUSAGE;
}
no_args (list->next);
status = sval & 255;
return status;
}
/* Return the octal number parsed from STRING, or -1 to indicate
that the string contained a bad number. */
int
read_octal (string)
char *string;
{
int result, digits;
result = digits = 0;
while (*string && ISOCTAL (*string))
{
digits++;
result = (result * 8) + (*string++ - '0');
if (result > 0777)
return -1;
}
if (digits == 0 || *string)
result = -1;
return (result);
}
/* **************************************************************** */
/* */
/* Manipulating the current working directory */
/* */
/* **************************************************************** */
/* Return a consed string which is the current working directory.
FOR_WHOM is the name of the caller for error printing. */
char *the_current_working_directory = (char *)NULL;
char *
get_working_directory (for_whom)
char *for_whom;
{
if (no_symbolic_links)
{
FREE (the_current_working_directory);
the_current_working_directory = (char *)NULL;
}
if (the_current_working_directory == 0)
{
#if defined (GETCWD_BROKEN)
the_current_working_directory = getcwd (0, PATH_MAX);
#else
the_current_working_directory = getcwd (0, 0);
#endif
if (the_current_working_directory == 0)
{
fprintf (stderr, _("%s: error retrieving current directory: %s: %s\n"),
(for_whom && *for_whom) ? for_whom : get_name_for_error (),
_(bash_getcwd_errstr), strerror (errno));
return (char *)NULL;
}
}
return (savestring (the_current_working_directory));
}
/* Make NAME our internal idea of the current working directory. */
void
set_working_directory (name)
char *name;
{
FREE (the_current_working_directory);
the_current_working_directory = savestring (name);
}
/* **************************************************************** */
/* */
/* Job control support functions */
/* */
/* **************************************************************** */
#if defined (JOB_CONTROL)
int
get_job_by_name (name, flags)
const char *name;
int flags;
{
register int i, wl, cl, match, job;
register PROCESS *p;
register JOB *j;
job = NO_JOB;
wl = strlen (name);
for (i = js.j_jobslots - 1; i >= 0; i--)
{
j = get_job_by_jid (i);
if (j == 0 || ((flags & JM_STOPPED) && J_JOBSTATE(j) != JSTOPPED))
continue;
p = j->pipe;
do
{
if (flags & JM_EXACT)
{
cl = strlen (p->command);
match = STREQN (p->command, name, cl);
}
else if (flags & JM_SUBSTRING)
match = strcasestr (p->command, name) != (char *)0;
else
match = STREQN (p->command, name, wl);
if (match == 0)
{
p = p->next;
continue;
}
else if (flags & JM_FIRSTMATCH)
return i; /* return first match */
else if (job != NO_JOB)
{
if (this_shell_builtin)
builtin_error (_("%s: ambiguous job spec"), name);
else
internal_error (_("%s: ambiguous job spec"), name);
return (DUP_JOB);
}
else
job = i;
}
while (p != j->pipe);
}
return (job);
}
/* Return the job spec found in LIST. */
int
get_job_spec (list)
WORD_LIST *list;
{
register char *word;
int job, jflags;
if (list == 0)
return (js.j_current);
word = list->word->word;
if (*word == '\0')
return (NO_JOB);
if (*word == '%')
word++;
if (DIGIT (*word) && all_digits (word))
{
job = atoi (word);
return (job > js.j_jobslots ? NO_JOB : job - 1);
}
jflags = 0;
switch (*word)
{
case 0:
case '%':
case '+':
return (js.j_current);
case '-':
return (js.j_previous);
case '?': /* Substring search requested. */
jflags |= JM_SUBSTRING;
word++;
/* FALLTHROUGH */
default:
return get_job_by_name (word, jflags);
}
}
#endif /* JOB_CONTROL */
/*
* NOTE: `kill' calls this function with forcecols == 0
*/
int
display_signal_list (list, forcecols)
WORD_LIST *list;
int forcecols;
{
register int i, column;
char *name;
int result, signum, dflags;
intmax_t lsignum;
result = EXECUTION_SUCCESS;
if (!list)
{
for (i = 1, column = 0; i < NSIG; i++)
{
name = signal_name (i);
if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
continue;
if (posixly_correct && !forcecols)
{
/* This is for the kill builtin. POSIX.2 says the signal names
are displayed without the `SIG' prefix. */
if (STREQN (name, "SIG", 3))
name += 3;
printf ("%s%s", name, (i == NSIG - 1) ? "" : " ");
}
else
{
printf ("%2d) %s", i, name);
if (++column < 5)
printf ("\t");
else
{
printf ("\n");
column = 0;
}
}
}
if ((posixly_correct && !forcecols) || column != 0)
printf ("\n");
return result;
}
/* List individual signal names or numbers. */
while (list)
{
if (legal_number (list->word->word, &lsignum))
{
/* This is specified by Posix.2 so that exit statuses can be
mapped into signal numbers. */
if (lsignum > 128)
lsignum -= 128;
if (lsignum < 0 || lsignum >= NSIG)
{
sh_invalidsig (list->word->word);
result = EXECUTION_FAILURE;
list = list->next;
continue;
}
signum = lsignum;
name = signal_name (signum);
if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
{
list = list->next;
continue;
}
#if defined (JOB_CONTROL)
/* POSIX.2 says that `kill -l signum' prints the signal name without
the `SIG' prefix. */
printf ("%s\n", (this_shell_builtin == kill_builtin) ? name + 3 : name);
#else
printf ("%s\n", name);
#endif
}
else
{
dflags = DSIG_NOCASE;
if (posixly_correct == 0 || this_shell_builtin != kill_builtin)
dflags |= DSIG_SIGPREFIX;
signum = decode_signal (list->word->word, dflags);
if (signum == NO_SIG)
{
sh_invalidsig (list->word->word);
result = EXECUTION_FAILURE;
list = list->next;
continue;
}
printf ("%d\n", signum);
}
list = list->next;
}
return (result);
}
/* **************************************************************** */
/* */
/* Finding builtin commands and their functions */
/* */
/* **************************************************************** */
/* Perform a binary search and return the address of the builtin function
whose name is NAME. If the function couldn't be found, or the builtin
is disabled or has no function associated with it, return NULL.
Return the address of the builtin.
DISABLED_OKAY means find it even if the builtin is disabled. */
struct builtin *
builtin_address_internal (name, disabled_okay)
char *name;
int disabled_okay;
{
int hi, lo, mid, j;
hi = num_shell_builtins - 1;
lo = 0;
while (lo <= hi)
{
mid = (lo + hi) / 2;
j = shell_builtins[mid].name[0] - name[0];
if (j == 0)
j = strcmp (shell_builtins[mid].name, name);
if (j == 0)
{
/* It must have a function pointer. It must be enabled, or we
must have explicitly allowed disabled functions to be found,
and it must not have been deleted. */
if (shell_builtins[mid].function &&
((shell_builtins[mid].flags & BUILTIN_DELETED) == 0) &&
((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay))
return (&shell_builtins[mid]);
else
return ((struct builtin *)NULL);
}
if (j > 0)
hi = mid - 1;
else
lo = mid + 1;
}
return ((struct builtin *)NULL);
}
/* Return the pointer to the function implementing builtin command NAME. */
sh_builtin_func_t *
find_shell_builtin (name)
char *name;
{
current_builtin = builtin_address_internal (name, 0);
return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
}
/* Return the address of builtin with NAME, whether it is enabled or not. */
sh_builtin_func_t *
builtin_address (name)
char *name;
{
current_builtin = builtin_address_internal (name, 1);
return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
}
/* Return the function implementing the builtin NAME, but only if it is a
POSIX.2 special builtin. */
sh_builtin_func_t *
find_special_builtin (name)
char *name;
{
current_builtin = builtin_address_internal (name, 0);
return ((current_builtin && (current_builtin->flags & SPECIAL_BUILTIN)) ?
current_builtin->function :
(sh_builtin_func_t *)NULL);
}
static int
shell_builtin_compare (sbp1, sbp2)
struct builtin *sbp1, *sbp2;
{
int result;
if ((result = sbp1->name[0] - sbp2->name[0]) == 0)
result = strcmp (sbp1->name, sbp2->name);
return (result);
}
/* Sort the table of shell builtins so that the binary search will work
in find_shell_builtin. */
void
initialize_shell_builtins ()
{
qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin),
(QSFUNC *)shell_builtin_compare);
}
+1 -1
View File
@@ -126,7 +126,7 @@ copy_redirect (redirect)
{
case r_reading_until:
case r_deblank_reading_until:
new_redirect->here_doc_eof = savestring (redirect->here_doc_eof);
new_redirect->here_doc_eof = redirect->here_doc_eof ? savestring (redirect->here_doc_eof) : 0;
/*FALLTHROUGH*/
case r_reading_string:
case r_appending_to:
+453
View File
@@ -0,0 +1,453 @@
/* copy_command.c -- copy a COMMAND structure. This is needed
primarily for making function definitions, but I'm not sure
that anyone else will need it. */
/* Copyright (C) 1987-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"
#include "bashtypes.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include "shell.h"
static PATTERN_LIST *copy_case_clause __P((PATTERN_LIST *));
static PATTERN_LIST *copy_case_clauses __P((PATTERN_LIST *));
static FOR_COM *copy_for_command __P((FOR_COM *));
#if defined (ARITH_FOR_COMMAND)
static ARITH_FOR_COM *copy_arith_for_command __P((ARITH_FOR_COM *));
#endif
static GROUP_COM *copy_group_command __P((GROUP_COM *));
static SUBSHELL_COM *copy_subshell_command __P((SUBSHELL_COM *));
static COPROC_COM *copy_coproc_command __P((COPROC_COM *));
static CASE_COM *copy_case_command __P((CASE_COM *));
static WHILE_COM *copy_while_command __P((WHILE_COM *));
static IF_COM *copy_if_command __P((IF_COM *));
#if defined (DPAREN_ARITHMETIC)
static ARITH_COM *copy_arith_command __P((ARITH_COM *));
#endif
#if defined (COND_COMMAND)
static COND_COM *copy_cond_command __P((COND_COM *));
#endif
static SIMPLE_COM *copy_simple_command __P((SIMPLE_COM *));
WORD_DESC *
copy_word (w)
WORD_DESC *w;
{
WORD_DESC *new_word;
new_word = make_bare_word (w->word);
new_word->flags = w->flags;
return (new_word);
}
/* Copy the chain of words in LIST. Return a pointer to
the new chain. */
WORD_LIST *
copy_word_list (list)
WORD_LIST *list;
{
WORD_LIST *new_list;
for (new_list = (WORD_LIST *)NULL; list; list = list->next)
new_list = make_word_list (copy_word (list->word), new_list);
return (REVERSE_LIST (new_list, WORD_LIST *));
}
static PATTERN_LIST *
copy_case_clause (clause)
PATTERN_LIST *clause;
{
PATTERN_LIST *new_clause;
new_clause = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST));
new_clause->patterns = copy_word_list (clause->patterns);
new_clause->action = copy_command (clause->action);
new_clause->flags = clause->flags;
return (new_clause);
}
static PATTERN_LIST *
copy_case_clauses (clauses)
PATTERN_LIST *clauses;
{
PATTERN_LIST *new_list, *new_clause;
for (new_list = (PATTERN_LIST *)NULL; clauses; clauses = clauses->next)
{
new_clause = copy_case_clause (clauses);
new_clause->next = new_list;
new_list = new_clause;
}
return (REVERSE_LIST (new_list, PATTERN_LIST *));
}
/* Copy a single redirect. */
REDIRECT *
copy_redirect (redirect)
REDIRECT *redirect;
{
REDIRECT *new_redirect;
new_redirect = (REDIRECT *)xmalloc (sizeof (REDIRECT));
#if 0
FASTCOPY ((char *)redirect, (char *)new_redirect, (sizeof (REDIRECT)));
#else
*new_redirect = *redirect; /* let the compiler do the fast structure copy */
#endif
if (redirect->rflags & REDIR_VARASSIGN)
new_redirect->redirector.filename = copy_word (redirect->redirector.filename);
switch (redirect->instruction)
{
case r_reading_until:
case r_deblank_reading_until:
if (redirect->here_doc_eof)
new_redirect->here_doc_eof = savestring (redirect->here_doc_eof);
else
new_redirect->here_doc_eof = 0;
/*FALLTHROUGH*/
case r_reading_string:
case r_appending_to:
case r_output_direction:
case r_input_direction:
case r_inputa_direction:
case r_err_and_out:
case r_append_err_and_out:
case r_input_output:
case r_output_force:
case r_duplicating_input_word:
case r_duplicating_output_word:
case r_move_input_word:
case r_move_output_word:
new_redirect->redirectee.filename = copy_word (redirect->redirectee.filename);
break;
case r_duplicating_input:
case r_duplicating_output:
case r_move_input:
case r_move_output:
case r_close_this:
break;
}
return (new_redirect);
}
REDIRECT *
copy_redirects (list)
REDIRECT *list;
{
REDIRECT *new_list, *temp;
for (new_list = (REDIRECT *)NULL; list; list = list->next)
{
temp = copy_redirect (list);
temp->next = new_list;
new_list = temp;
}
return (REVERSE_LIST (new_list, REDIRECT *));
}
static FOR_COM *
copy_for_command (com)
FOR_COM *com;
{
FOR_COM *new_for;
new_for = (FOR_COM *)xmalloc (sizeof (FOR_COM));
new_for->flags = com->flags;
new_for->line = com->line;
new_for->name = copy_word (com->name);
new_for->map_list = copy_word_list (com->map_list);
new_for->action = copy_command (com->action);
return (new_for);
}
#if defined (ARITH_FOR_COMMAND)
static ARITH_FOR_COM *
copy_arith_for_command (com)
ARITH_FOR_COM *com;
{
ARITH_FOR_COM *new_arith_for;
new_arith_for = (ARITH_FOR_COM *)xmalloc (sizeof (ARITH_FOR_COM));
new_arith_for->flags = com->flags;
new_arith_for->line = com->line;
new_arith_for->init = copy_word_list (com->init);
new_arith_for->test = copy_word_list (com->test);
new_arith_for->step = copy_word_list (com->step);
new_arith_for->action = copy_command (com->action);
return (new_arith_for);
}
#endif /* ARITH_FOR_COMMAND */
static GROUP_COM *
copy_group_command (com)
GROUP_COM *com;
{
GROUP_COM *new_group;
new_group = (GROUP_COM *)xmalloc (sizeof (GROUP_COM));
new_group->command = copy_command (com->command);
return (new_group);
}
static SUBSHELL_COM *
copy_subshell_command (com)
SUBSHELL_COM *com;
{
SUBSHELL_COM *new_subshell;
new_subshell = (SUBSHELL_COM *)xmalloc (sizeof (SUBSHELL_COM));
new_subshell->command = copy_command (com->command);
new_subshell->flags = com->flags;
return (new_subshell);
}
static COPROC_COM *
copy_coproc_command (com)
COPROC_COM *com;
{
COPROC_COM *new_coproc;
new_coproc = (COPROC_COM *)xmalloc (sizeof (COPROC_COM));
new_coproc->name = savestring (com->name);
new_coproc->command = copy_command (com->command);
new_coproc->flags = com->flags;
return (new_coproc);
}
static CASE_COM *
copy_case_command (com)
CASE_COM *com;
{
CASE_COM *new_case;
new_case = (CASE_COM *)xmalloc (sizeof (CASE_COM));
new_case->flags = com->flags;
new_case->line = com->line;
new_case->word = copy_word (com->word);
new_case->clauses = copy_case_clauses (com->clauses);
return (new_case);
}
static WHILE_COM *
copy_while_command (com)
WHILE_COM *com;
{
WHILE_COM *new_while;
new_while = (WHILE_COM *)xmalloc (sizeof (WHILE_COM));
new_while->flags = com->flags;
new_while->test = copy_command (com->test);
new_while->action = copy_command (com->action);
return (new_while);
}
static IF_COM *
copy_if_command (com)
IF_COM *com;
{
IF_COM *new_if;
new_if = (IF_COM *)xmalloc (sizeof (IF_COM));
new_if->flags = com->flags;
new_if->test = copy_command (com->test);
new_if->true_case = copy_command (com->true_case);
new_if->false_case = com->false_case ? copy_command (com->false_case) : com->false_case;
return (new_if);
}
#if defined (DPAREN_ARITHMETIC)
static ARITH_COM *
copy_arith_command (com)
ARITH_COM *com;
{
ARITH_COM *new_arith;
new_arith = (ARITH_COM *)xmalloc (sizeof (ARITH_COM));
new_arith->flags = com->flags;
new_arith->exp = copy_word_list (com->exp);
new_arith->line = com->line;
return (new_arith);
}
#endif
#if defined (COND_COMMAND)
static COND_COM *
copy_cond_command (com)
COND_COM *com;
{
COND_COM *new_cond;
new_cond = (COND_COM *)xmalloc (sizeof (COND_COM));
new_cond->flags = com->flags;
new_cond->line = com->line;
new_cond->type = com->type;
new_cond->op = com->op ? copy_word (com->op) : com->op;
new_cond->left = com->left ? copy_cond_command (com->left) : (COND_COM *)NULL;
new_cond->right = com->right ? copy_cond_command (com->right) : (COND_COM *)NULL;
return (new_cond);
}
#endif
static SIMPLE_COM *
copy_simple_command (com)
SIMPLE_COM *com;
{
SIMPLE_COM *new_simple;
new_simple = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM));
new_simple->flags = com->flags;
new_simple->words = copy_word_list (com->words);
new_simple->redirects = com->redirects ? copy_redirects (com->redirects) : (REDIRECT *)NULL;
new_simple->line = com->line;
return (new_simple);
}
FUNCTION_DEF *
copy_function_def_contents (old, new_def)
FUNCTION_DEF *old, *new_def;
{
new_def->name = copy_word (old->name);
new_def->command = old->command ? copy_command (old->command) : old->command;
new_def->flags = old->flags;
new_def->line = old->line;
new_def->source_file = old->source_file ? savestring (old->source_file) : old->source_file;
return (new_def);
}
FUNCTION_DEF *
copy_function_def (com)
FUNCTION_DEF *com;
{
FUNCTION_DEF *new_def;
new_def = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF));
new_def = copy_function_def_contents (com, new_def);
return (new_def);
}
/* Copy the command structure in COMMAND. Return a pointer to the
copy. Don't you forget to dispose_command () on this pointer
later! */
COMMAND *
copy_command (command)
COMMAND *command;
{
COMMAND *new_command;
if (command == NULL)
return (command);
new_command = (COMMAND *)xmalloc (sizeof (COMMAND));
FASTCOPY ((char *)command, (char *)new_command, sizeof (COMMAND));
new_command->flags = command->flags;
new_command->line = command->line;
if (command->redirects)
new_command->redirects = copy_redirects (command->redirects);
switch (command->type)
{
case cm_for:
new_command->value.For = copy_for_command (command->value.For);
break;
#if defined (ARITH_FOR_COMMAND)
case cm_arith_for:
new_command->value.ArithFor = copy_arith_for_command (command->value.ArithFor);
break;
#endif
#if defined (SELECT_COMMAND)
case cm_select:
new_command->value.Select =
(SELECT_COM *)copy_for_command ((FOR_COM *)command->value.Select);
break;
#endif
case cm_group:
new_command->value.Group = copy_group_command (command->value.Group);
break;
case cm_subshell:
new_command->value.Subshell = copy_subshell_command (command->value.Subshell);
break;
case cm_coproc:
new_command->value.Coproc = copy_coproc_command (command->value.Coproc);
break;
case cm_case:
new_command->value.Case = copy_case_command (command->value.Case);
break;
case cm_until:
case cm_while:
new_command->value.While = copy_while_command (command->value.While);
break;
case cm_if:
new_command->value.If = copy_if_command (command->value.If);
break;
#if defined (DPAREN_ARITHMETIC)
case cm_arith:
new_command->value.Arith = copy_arith_command (command->value.Arith);
break;
#endif
#if defined (COND_COMMAND)
case cm_cond:
new_command->value.Cond = copy_cond_command (command->value.Cond);
break;
#endif
case cm_simple:
new_command->value.Simple = copy_simple_command (command->value.Simple);
break;
case cm_connection:
{
CONNECTION *new_connection;
new_connection = (CONNECTION *)xmalloc (sizeof (CONNECTION));
new_connection->connector = command->value.Connection->connector;
new_connection->first = copy_command (command->value.Connection->first);
new_connection->second = copy_command (command->value.Connection->second);
new_command->value.Connection = new_connection;
break;
}
case cm_function_def:
new_command->value.Function_def = copy_function_def (command->value.Function_def);
break;
}
return (new_command);
}
+42
View File
@@ -0,0 +1,42 @@
# This file is a shell script that caches the results of configure
# tests for CYGWIN32 so they don't need to be done when cross-compiling.
# AC_FUNC_GETPGRP should also define GETPGRP_VOID
ac_cv_func_getpgrp_void=${ac_cv_func_getpgrp_void='yes'}
# AC_FUNC_SETVBUF_REVERSED should not define anything else
ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed='no'}
# on CYGWIN32, system calls do not restart
ac_cv_sys_restartable_syscalls=${ac_cv_sys_restartable_syscalls='no'}
bash_cv_sys_restartable_syscalls=${bash_cv_sys_restartable_syscalls='no'}
# these may be necessary, but they are currently commented out
#ac_cv_c_bigendian=${ac_cv_c_bigendian='no'}
ac_cv_sizeof_char_p=${ac_cv_sizeof_char_p='4'}
ac_cv_sizeof_int=${ac_cv_sizeof_int='4'}
ac_cv_sizeof_long=${ac_cv_sizeof_long='4'}
ac_cv_sizeof_double=${ac_cv_sizeof_double='8'}
bash_cv_dup2_broken=${bash_cv_dup2_broken='no'}
bash_cv_pgrp_pipe=${bash_cv_pgrp_pipe='no'}
bash_cv_type_rlimit=${bash_cv_type_rlimit='long'}
bash_cv_decl_under_sys_siglist=${bash_cv_decl_under_sys_siglist='no'}
bash_cv_under_sys_siglist=${bash_cv_under_sys_siglist='no'}
bash_cv_sys_siglist=${bash_cv_sys_siglist='no'}
bash_cv_opendir_not_robust=${bash_cv_opendir_not_robust='no'}
bash_cv_getenv_redef=${bash_cv_getenv_redef='yes'}
bash_cv_printf_declared=${bash_cv_printf_declared='yes'}
bash_cv_ulimit_maxfds=${bash_cv_ulimit_maxfds='no'}
bash_cv_getcwd_calls_popen=${bash_cv_getcwd_calls_popen='no'}
bash_cv_must_reinstall_sighandlers=${bash_cv_must_reinstall_sighandlers='no'}
bash_cv_job_control_missing=${bash_cv_job_control_missing='present'}
bash_cv_sys_named_pipes=${bash_cv_sys_named_pipes='missing'}
bash_cv_func_sigsetjmp=${bash_cv_func_sigsetjmp='missing'}
bash_cv_mail_dir=${bash_cv_mail_dir='unknown'}
bash_cv_func_strcoll_broken=${bash_cv_func_strcoll_broken='no'}
bash_cv_type_int32_t=${bash_cv_type_int32_t='int'}
bash_cv_type_u_int32_t=${bash_cv_type_u_int32_t='int'}
ac_cv_type_bits64_t=${ac_cv_type_bits64_t='no'}
# end of cross-build/cygwin32.cache
+1745
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
+2101 -1089
View File
File diff suppressed because it is too large Load Diff
+238
View File
@@ -0,0 +1,238 @@
#
# Simple makefile for the sample loadable builtins
#
# Copyright (C) 1996 Free Software Foundation, Inc.
# This program 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.
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
# Include some boilerplate Gnu makefile definitions.
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
libdir = @libdir@
infodir = @infodir@
includedir = @includedir@
topdir = @top_srcdir@
BUILD_DIR = @BUILD_DIR@
srcdir = @srcdir@
VPATH = .:@srcdir@
@SET_MAKE@
CC = @CC@
RM = rm -f
SHELL = @MAKE_SHELL@
host_os = @host_os@
host_cpu = @host_cpu@
host_vendor = @host_vendor@
CFLAGS = @CFLAGS@
LOCAL_CFLAGS = @LOCAL_CFLAGS@
DEFS = @DEFS@
LOCAL_DEFS = @LOCAL_DEFS@
CPPFLAGS = @CPPFLAGS@
BASHINCDIR = ${topdir}/include
LIBBUILD = ${BUILD_DIR}/lib
INTL_LIBSRC = ${topdir}/lib/intl
INTL_BUILDDIR = ${LIBBUILD}/intl
INTL_INC = @INTL_INC@
LIBINTL_H = @LIBINTL_H@
CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS)
#
# These values are generated for configure by ${topdir}/support/shobj-conf.
# If your system is not supported by that script, but includes facilities for
# dynamic loading of shared objects, please update the script and send the
# changes to bash-maintainers@gnu.org.
#
SHOBJ_CC = @SHOBJ_CC@
SHOBJ_CFLAGS = @SHOBJ_CFLAGS@
SHOBJ_LD = @SHOBJ_LD@
SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@
SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@
SHOBJ_LIBS = @SHOBJ_LIBS@
SHOBJ_STATUS = @SHOBJ_STATUS@
INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \
-I$(BASHINCDIR) -I$(BUILD_DIR) -I$(LIBBUILD) \
-I$(BUILD_DIR)/builtins $(INTL_INC)
.c.o:
$(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CCFLAGS) $(INC) -c -o $@ $<
ALLPROG = print truefalse sleep pushd finfo logname basename dirname \
tty pathchk tee head mkdir rmdir printenv id whoami \
uname sync push ln unlink cut realpath getconf strftime
OTHERPROG = necho hello cat
all: $(SHOBJ_STATUS)
supported: $(ALLPROG)
others: $(OTHERPROG)
unsupported:
@echo "Your system (${host_os}) is not supported by the"
@echo "${topdir}/support/shobj-conf script."
@echo "If your operating system provides facilities for dynamic"
@echo "loading of shared objects using the dlopen(3) interface,"
@echo "please update the script and re-run configure.
@echo "Please send the changes you made to bash-maintainers@gnu.org"
@echo "for inclusion in future bash releases."
everything: supported others
print: print.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ print.o $(SHOBJ_LIBS)
necho: necho.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ necho.o $(SHOBJ_LIBS)
getconf: getconf.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ getconf.o $(SHOBJ_LIBS)
hello: hello.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ hello.o $(SHOBJ_LIBS)
truefalse: truefalse.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ truefalse.o $(SHOBJ_LIBS)
sleep: sleep.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sleep.o $(SHOBJ_LIBS)
finfo: finfo.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ finfo.o $(SHOBJ_LIBS)
cat: cat.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cat.o $(SHOBJ_LIBS)
logname: logname.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS)
basename: basename.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ basename.o $(SHOBJ_LIBS)
dirname: dirname.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ dirname.o $(SHOBJ_LIBS)
tty: tty.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tty.o $(SHOBJ_LIBS)
pathchk: pathchk.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pathchk.o $(SHOBJ_LIBS)
tee: tee.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tee.o $(SHOBJ_LIBS)
mkdir: mkdir.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mkdir.o $(SHOBJ_LIBS)
rmdir: rmdir.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rmdir.o $(SHOBJ_LIBS)
head: head.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ head.o $(SHOBJ_LIBS)
printenv: printenv.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ printenv.o $(SHOBJ_LIBS)
id: id.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ id.o $(SHOBJ_LIBS)
whoami: whoami.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ whoami.o $(SHOBJ_LIBS)
uname: uname.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ uname.o $(SHOBJ_LIBS)
sync: sync.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sync.o $(SHOBJ_LIBS)
push: push.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ push.o $(SHOBJ_LIBS)
ln: ln.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ ln.o $(SHOBJ_LIBS)
unlink: unlink.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ unlink.o $(SHOBJ_LIBS)
cut: cut.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cut.o $(SHOBJ_LIBS)
realpath: realpath.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ realpath.o $(SHOBJ_LIBS)
strftime: strftime.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ strftime.o $(SHOBJ_LIBS)
# pushd is a special case. We use the same source that the builtin version
# uses, with special compilation options.
#
pushd.c: ${topdir}/builtins/pushd.def
$(RM) $@
${BUILD_DIR}/builtins/mkbuiltins -D ${topdir}/builtins ${topdir}/builtins/pushd.def
pushd.o: pushd.c
$(RM) $@
$(SHOBJ_CC) -DHAVE_CONFIG_H -DPUSHD_AND_POPD -DLOADABLE_BUILTIN $(SHOBJ_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(INC) -c -o $@ $<
pushd: pushd.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pushd.o $(SHOBJ_LIBS)
clean:
$(RM) $(ALLPROG) $(OTHERPROG) *.o
-( cd perl && ${MAKE} ${MFLAGS} $@ )
mostlyclean: clean
-( cd perl && ${MAKE} ${MFLAGS} $@ )
distclean maintainer-clean: clean
$(RM) Makefile pushd.c
-( cd perl && ${MAKE} ${MFLAGS} $@ )
print.o: print.c
truefalse.o: truefalse.c
sleep.o: sleep.c
finfo.o: finfo.c
logname.o: logname.c
basename.o: basename.c
dirname.o: dirname.c
tty.o: tty.c
pathchk.o: pathchk.c
tee.o: tee.c
head.o: head.c
rmdir.o: rmdir.c
necho.o: necho.c
getconf.o: getconf.c
hello.o: hello.c
cat.o: cat.c
printenv.o: printenv.c
id.o: id.c
whoami.o: whoami.c
uname.o: uname.c
sync.o: sync.c
push.o: push.c
mkdir.o: mkdir.c
realpath.o: realpath.c
strftime.o: strftime.c
+2
View File
@@ -5416,7 +5416,9 @@ shell_execve (command, args, env)
unbind_args (); /* remove the positional parameters */
#if defined (PROCESS_SUBSTITUTION)
clear_fifo_list (); /* pipe fds are what they are now */
#endif
longjmp (subshell_top_level, 1);
/*NOTREACHED*/
+5538
View File
File diff suppressed because it is too large Load Diff
+10
View File
@@ -53,6 +53,7 @@ extern int interactive_comments;
extern int check_hashed_filenames;
extern int source_uses_path;
extern int source_searches_cwd;
extern int posixly_correct;
static char *bash_special_tilde_expansions __P((char *));
static int unquoted_tilde_word __P((const char *));
@@ -244,6 +245,15 @@ check_identifier (word, check_word)
return (1);
}
int
legal_function_name (string)
char *string;
{
if (absolute_program (string)) /* don't allow slash */
return 0;
return (posixly_correct ? legal_identifier (string) : 1);
}
/* Return 1 if STRING comprises a valid alias name. The shell accepts
essentially all characters except those which must be quoted to the
parser (which disqualifies them from alias expansion anyway) and `/'. */
+1207
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -283,6 +283,7 @@ extern void print_rlimtype __P((RLIMTYPE, int));
extern int all_digits __P((char *));
extern int legal_number __P((const char *, intmax_t *));
extern int legal_identifier __P((char *));
extern int legal_function_name __P((char *));
extern int check_identifier __P((WORD_DESC *, int));
extern int legal_alias_name __P((char *, int));
extern int assignment __P((const char *, int));
+328
View File
@@ -0,0 +1,328 @@
/* general.h -- defines that everybody likes to use. */
/* Copyright (C) 1993-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/>.
*/
#if !defined (_GENERAL_H_)
#define _GENERAL_H_
#include "stdc.h"
#include "bashtypes.h"
#include "chartypes.h"
#if defined (HAVE_SYS_RESOURCE_H) && defined (RLIMTYPE)
# if defined (HAVE_SYS_TIME_H)
# include <sys/time.h>
# endif
# include <sys/resource.h>
#endif
#if defined (HAVE_STRING_H)
# include <string.h>
#else
# include <strings.h>
#endif /* !HAVE_STRING_H */
#if defined (HAVE_LIMITS_H)
# include <limits.h>
#endif
#include "xmalloc.h"
/* NULL pointer type. */
#if !defined (NULL)
# if defined (__STDC__)
# define NULL ((void *) 0)
# else
# define NULL 0x0
# endif /* !__STDC__ */
#endif /* !NULL */
/* Hardly used anymore */
#define pointer_to_int(x) (int)((char *)x - (char *)0)
#if defined (alpha) && defined (__GNUC__) && !defined (strchr) && !defined (__STDC__)
extern char *strchr (), *strrchr ();
#endif
#if !defined (strcpy) && (defined (HAVE_DECL_STRCPY) && !HAVE_DECL_STRCPY)
extern char *strcpy __P((char *, const char *));
#endif
#if !defined (savestring)
# define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
#endif
#ifndef member
# define member(c, s) ((c) ? ((char *)mbschr ((s), (c)) != (char *)NULL) : 0)
#endif
#ifndef whitespace
#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
#endif
#ifndef CHAR_MAX
# ifdef __CHAR_UNSIGNED__
# define CHAR_MAX 0xff
# else
# define CHAR_MAX 0x7f
# endif
#endif
#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif
/* Nonzero if the integer type T is signed. */
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
/* Bound on length of the string representing an integer value of type T.
Subtract one for the sign bit if T is signed;
302 / 1000 is log10 (2) rounded up;
add one for integer division truncation;
add one more for a minus sign if t is signed. */
#define INT_STRLEN_BOUND(t) \
((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \
+ 1 + TYPE_SIGNED (t))
/* Define exactly what a legal shell identifier consists of. */
#define legal_variable_starter(c) (ISALPHA(c) || (c == '_'))
#define legal_variable_char(c) (ISALNUM(c) || c == '_')
/* Definitions used in subst.c and by the `read' builtin for field
splitting. */
#define spctabnl(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
/* All structs which contain a `next' field should have that field
as the first field in the struct. This means that functions
can be written to handle the general case for linked lists. */
typedef struct g_list {
struct g_list *next;
} GENERIC_LIST;
/* Here is a generic structure for associating character strings
with integers. It is used in the parser for shell tokenization. */
typedef struct {
char *word;
int token;
} STRING_INT_ALIST;
/* A macro to avoid making an unneccessary function call. */
#define REVERSE_LIST(list, type) \
((list && list->next) ? (type)list_reverse ((GENERIC_LIST *)list) \
: (type)(list))
#if __GNUC__ > 1
# define FASTCOPY(s, d, n) __builtin_memcpy ((d), (s), (n))
#else /* !__GNUC__ */
# if !defined (HAVE_BCOPY)
# if !defined (HAVE_MEMMOVE)
# define FASTCOPY(s, d, n) memcpy ((d), (s), (n))
# else
# define FASTCOPY(s, d, n) memmove ((d), (s), (n))
# endif /* !HAVE_MEMMOVE */
# else /* HAVE_BCOPY */
# define FASTCOPY(s, d, n) bcopy ((s), (d), (n))
# endif /* HAVE_BCOPY */
#endif /* !__GNUC__ */
/* String comparisons that possibly save a function call each. */
#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
#define STREQN(a, b, n) ((n == 0) ? (1) \
: ((a)[0] == (b)[0] && strncmp(a, b, n) == 0))
/* More convenience definitions that possibly save system or libc calls. */
#define STRLEN(s) (((s) && (s)[0]) ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0)
#define FREE(s) do { if (s) free (s); } while (0)
#define MEMBER(c, s) (((c) && c == (s)[0] && !(s)[1]) || (member(c, s)))
/* A fairly hairy macro to check whether an allocated string has more room,
and to resize it using xrealloc if it does not.
STR is the string (char *)
CIND is the current index into the string (int)
ROOM is the amount of additional room we need in the string (int)
CSIZE is the currently-allocated size of STR (int)
SINCR is how much to increment CSIZE before calling xrealloc (int) */
#define RESIZE_MALLOCED_BUFFER(str, cind, room, csize, sincr) \
do { \
if ((cind) + (room) >= csize) \
{ \
while ((cind) + (room) >= csize) \
csize += (sincr); \
str = xrealloc (str, csize); \
} \
} while (0)
/* Function pointers can be declared as (Function *)foo. */
#if !defined (_FUNCTION_DEF)
# define _FUNCTION_DEF
typedef int Function ();
typedef void VFunction ();
typedef char *CPFunction (); /* no longer used */
typedef char **CPPFunction (); /* no longer used */
#endif /* _FUNCTION_DEF */
#ifndef SH_FUNCTION_TYPEDEF
# define SH_FUNCTION_TYPEDEF
/* Shell function typedefs with prototypes */
/* `Generic' function pointer typedefs */
typedef int sh_intfunc_t __P((int));
typedef int sh_ivoidfunc_t __P((void));
typedef int sh_icpfunc_t __P((char *));
typedef int sh_icppfunc_t __P((char **));
typedef int sh_iptrfunc_t __P((PTR_T));
typedef void sh_voidfunc_t __P((void));
typedef void sh_vintfunc_t __P((int));
typedef void sh_vcpfunc_t __P((char *));
typedef void sh_vcppfunc_t __P((char **));
typedef void sh_vptrfunc_t __P((PTR_T));
typedef int sh_wdesc_func_t __P((WORD_DESC *));
typedef int sh_wlist_func_t __P((WORD_LIST *));
typedef int sh_glist_func_t __P((GENERIC_LIST *));
typedef char *sh_string_func_t __P((char *)); /* like savestring, et al. */
typedef int sh_msg_func_t __P((const char *, ...)); /* printf(3)-like */
typedef void sh_vmsg_func_t __P((const char *, ...)); /* printf(3)-like */
/* Specific function pointer typedefs. Most of these could be done
with #defines. */
typedef void sh_sv_func_t __P((char *)); /* sh_vcpfunc_t */
typedef void sh_free_func_t __P((PTR_T)); /* sh_vptrfunc_t */
typedef void sh_resetsig_func_t __P((int)); /* sh_vintfunc_t */
typedef int sh_ignore_func_t __P((const char *)); /* sh_icpfunc_t */
typedef int sh_assign_func_t __P((const char *));
typedef int sh_wassign_func_t __P((WORD_DESC *, int));
typedef int sh_builtin_func_t __P((WORD_LIST *)); /* sh_wlist_func_t */
#endif /* SH_FUNCTION_TYPEDEF */
#define NOW ((time_t) time ((time_t *) 0))
/* Some defines for calling file status functions. */
#define FS_EXISTS 0x1
#define FS_EXECABLE 0x2
#define FS_EXEC_PREFERRED 0x4
#define FS_EXEC_ONLY 0x8
#define FS_DIRECTORY 0x10
#define FS_NODIRS 0x20
#define FS_READABLE 0x40
/* Default maximum for move_to_high_fd */
#define HIGH_FD_MAX 256
/* The type of function passed as the fourth argument to qsort(3). */
#ifdef __STDC__
typedef int QSFUNC (const void *, const void *);
#else
typedef int QSFUNC ();
#endif
/* Some useful definitions for Unix pathnames. Argument convention:
x == string, c == character */
#if !defined (__CYGWIN__)
# define ABSPATH(x) ((x)[0] == '/')
# define RELPATH(x) ((x)[0] != '/')
#else /* __CYGWIN__ */
# define ABSPATH(x) (((x)[0] && ISALPHA((unsigned char)(x)[0]) && (x)[1] == ':') || ISDIRSEP((x)[0]))
# define RELPATH(x) (ABSPATH(x) == 0)
#endif /* __CYGWIN__ */
#define ROOTEDPATH(x) (ABSPATH(x))
#define DIRSEP '/'
#if !defined (__CYGWIN__)
# define ISDIRSEP(c) ((c) == '/')
#else
# define ISDIRSEP(c) ((c) == '/' || (c) == '\\')
#endif /* __CYGWIN__ */
#define PATHSEP(c) (ISDIRSEP(c) || (c) == 0)
#if 0
/* Declarations for functions defined in xmalloc.c */
extern PTR_T xmalloc __P((size_t));
extern PTR_T xrealloc __P((void *, size_t));
extern void xfree __P((void *));
#endif
/* Declarations for functions defined in general.c */
extern void posix_initialize __P((int));
#if defined (RLIMTYPE)
extern RLIMTYPE string_to_rlimtype __P((char *));
extern void print_rlimtype __P((RLIMTYPE, int));
#endif
extern int all_digits __P((char *));
extern int legal_number __P((const char *, intmax_t *));
extern int legal_identifier __P((char *));
extern int check_identifier __P((WORD_DESC *, int));
extern int legal_alias_name __P((char *, int));
extern int assignment __P((const char *, int));
extern int sh_unset_nodelay_mode __P((int));
extern int sh_validfd __P((int));
extern int fd_ispipe __P((int));
extern void check_dev_tty __P((void));
extern int move_to_high_fd __P((int, int, int));
extern int check_binary_file __P((char *, int));
#ifdef _POSIXSTAT_H_
extern int same_file __P((char *, char *, struct stat *, struct stat *));
#endif
extern int sh_openpipe __P((int *));
extern int sh_closepipe __P((int *));
extern int file_exists __P((char *));
extern int file_isdir __P((char *));
extern int file_iswdir __P((char *));
extern int path_dot_or_dotdot __P((const char *));
extern int absolute_pathname __P((const char *));
extern int absolute_program __P((const char *));
extern char *make_absolute __P((char *, char *));
extern char *base_pathname __P((char *));
extern char *full_pathname __P((char *));
extern char *polite_directory_format __P((char *));
extern char *trim_pathname __P((char *, int));
extern char *printable_filename __P((char *, int));
extern char *extract_colon_unit __P((char *, int *));
extern void tilde_initialize __P((void));
extern char *bash_tilde_find_word __P((const char *, int, int *));
extern char *bash_tilde_expand __P((const char *, int));
extern int group_member __P((gid_t));
extern char **get_group_list __P((int *));
extern int *get_group_array __P((int *));
#endif /* _GENERAL_H_ */
+4
View File
@@ -42,7 +42,9 @@
#define WLPAREN L'('
#define WRPAREN L')'
/* Make sure these names continue to agree with what's in smatch.c */
extern char *glob_patscan __P((char *, char *, int));
extern wchar_t *glob_patscan_wc __P((wchar_t *, wchar_t *, int));
/* Return 1 of the first character of WSTRING could match the first
character of pattern WPAT. Wide character version. */
@@ -378,6 +380,7 @@ bad_bracket:
return matlen;
}
#if defined (EXTENDED_GLOB)
/* Skip characters in PAT and return the final occurrence of DIRSEP. This
is only called when extended_glob is set, so we have to skip over extglob
patterns x(...) */
@@ -408,3 +411,4 @@ glob_dirscan (pat, dirsep)
}
return d;
}
#endif /* EXTENDED_GLOB */
+412
View File
@@ -0,0 +1,412 @@
/* gmisc.c -- miscellaneous pattern matching utility functions for Bash.
Copyright (C) 2010 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>
#include "bashtypes.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "bashansi.h"
#include "shmbutil.h"
#include "stdc.h"
#ifndef LPAREN
# define LPAREN '('
#endif
#ifndef RPAREN
# define RPAREN ')'
#endif
#if defined (HANDLE_MULTIBYTE)
#define WLPAREN L'('
#define WRPAREN L')'
/* Make sure these names continue to agree with what's in smatch.c */
extern char *glob_patscan __P((char *, char *, int));
extern wchar_t *glob_patscan_wc __P((wchar_t *, wchar_t *, int));
/* Return 1 of the first character of WSTRING could match the first
character of pattern WPAT. Wide character version. */
int
match_pattern_wchar (wpat, wstring)
wchar_t *wpat, *wstring;
{
wchar_t wc;
if (*wstring == 0)
return (0);
switch (wc = *wpat++)
{
default:
return (*wstring == wc);
case L'\\':
return (*wstring == *wpat);
case L'?':
return (*wpat == WLPAREN ? 1 : (*wstring != L'\0'));
case L'*':
return (1);
case L'+':
case L'!':
case L'@':
return (*wpat == WLPAREN ? 1 : (*wstring == wc));
case L'[':
return (*wstring != L'\0');
}
}
int
wmatchlen (wpat, wmax)
wchar_t *wpat;
size_t wmax;
{
wchar_t wc;
int matlen, bracklen, t, in_cclass, in_collsym, in_equiv;
if (*wpat == 0)
return (0);
matlen = in_cclass = in_collsym = in_equiv = 0;
while (wc = *wpat++)
{
switch (wc)
{
default:
matlen++;
break;
case L'\\':
if (*wpat == 0)
return ++matlen;
else
{
matlen++;
wpat++;
}
break;
case L'?':
if (*wpat == WLPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case L'*':
return (matlen = -1);
case L'+':
case L'!':
case L'@':
if (*wpat == WLPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case L'[':
/* scan for ending `]', skipping over embedded [:...:] */
bracklen = 1;
wc = *wpat++;
do
{
if (wc == 0)
{
wpat--; /* back up to NUL */
matlen += bracklen;
goto bad_bracket;
}
else if (wc == L'\\')
{
/* *wpat == backslash-escaped character */
bracklen++;
/* If the backslash or backslash-escape ends the string,
bail. The ++wpat skips over the backslash escape */
if (*wpat == 0 || *++wpat == 0)
{
matlen += bracklen;
goto bad_bracket;
}
}
else if (wc == L'[' && *wpat == L':') /* character class */
{
wpat++;
bracklen++;
in_cclass = 1;
}
else if (in_cclass && wc == L':' && *wpat == L']')
{
wpat++;
bracklen++;
in_cclass = 0;
}
else if (wc == L'[' && *wpat == L'.') /* collating symbol */
{
wpat++;
bracklen++;
if (*wpat == L']') /* right bracket can appear as collating symbol */
{
wpat++;
bracklen++;
}
in_collsym = 1;
}
else if (in_collsym && wc == L'.' && *wpat == L']')
{
wpat++;
bracklen++;
in_collsym = 0;
}
else if (wc == L'[' && *wpat == L'=') /* equivalence class */
{
wpat++;
bracklen++;
if (*wpat == L']') /* right bracket can appear as equivalence class */
{
wpat++;
bracklen++;
}
in_equiv = 1;
}
else if (in_equiv && wc == L'=' && *wpat == L']')
{
wpat++;
bracklen++;
in_equiv = 0;
}
else
bracklen++;
}
while ((wc = *wpat++) != L']');
matlen++; /* bracket expression can only match one char */
bad_bracket:
break;
}
}
return matlen;
}
#endif
int
extglob_pattern_p (pat)
char *pat;
{
switch (pat[0])
{
case '*':
case '+':
case '!':
case '@':
case '?':
return (pat[1] == LPAREN);
default:
return 0;
}
return 0;
}
/* Return 1 of the first character of STRING could match the first
character of pattern PAT. Used to avoid n2 calls to strmatch(). */
int
match_pattern_char (pat, string)
char *pat, *string;
{
char c;
if (*string == 0)
return (0);
switch (c = *pat++)
{
default:
return (*string == c);
case '\\':
return (*string == *pat);
case '?':
return (*pat == LPAREN ? 1 : (*string != '\0'));
case '*':
return (1);
case '+':
case '!':
case '@':
return (*pat == LPAREN ? 1 : (*string == c));
case '[':
return (*string != '\0');
}
}
int
umatchlen (pat, max)
char *pat;
size_t max;
{
char c;
int matlen, bracklen, t, in_cclass, in_collsym, in_equiv;
if (*pat == 0)
return (0);
matlen = in_cclass = in_collsym = in_equiv = 0;
while (c = *pat++)
{
switch (c)
{
default:
matlen++;
break;
case '\\':
if (*pat == 0)
return ++matlen;
else
{
matlen++;
pat++;
}
break;
case '?':
if (*pat == LPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case '*':
return (matlen = -1);
case '+':
case '!':
case '@':
if (*pat == LPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case '[':
/* scan for ending `]', skipping over embedded [:...:] */
bracklen = 1;
c = *pat++;
do
{
if (c == 0)
{
pat--; /* back up to NUL */
matlen += bracklen;
goto bad_bracket;
}
else if (c == '\\')
{
/* *pat == backslash-escaped character */
bracklen++;
/* If the backslash or backslash-escape ends the string,
bail. The ++pat skips over the backslash escape */
if (*pat == 0 || *++pat == 0)
{
matlen += bracklen;
goto bad_bracket;
}
}
else if (c == '[' && *pat == ':') /* character class */
{
pat++;
bracklen++;
in_cclass = 1;
}
else if (in_cclass && c == ':' && *pat == ']')
{
pat++;
bracklen++;
in_cclass = 0;
}
else if (c == '[' && *pat == '.') /* collating symbol */
{
pat++;
bracklen++;
if (*pat == ']') /* right bracket can appear as collating symbol */
{
pat++;
bracklen++;
}
in_collsym = 1;
}
else if (in_collsym && c == '.' && *pat == ']')
{
pat++;
bracklen++;
in_collsym = 0;
}
else if (c == '[' && *pat == '=') /* equivalence class */
{
pat++;
bracklen++;
if (*pat == ']') /* right bracket can appear as equivalence class */
{
pat++;
bracklen++;
}
in_equiv = 1;
}
else if (in_equiv && c == '=' && *pat == ']')
{
pat++;
bracklen++;
in_equiv = 0;
}
else
bracklen++;
}
while ((c = *pat++) != ']');
matlen++; /* bracket expression can only match one char */
bad_bracket:
break;
}
}
return matlen;
}
/* Skip characters in PAT and return the final occurrence of DIRSEP. This
is only called when extended_glob is set, so we have to skip over extglob
patterns x(...) */
char *
glob_dirscan (pat, dirsep)
char *pat;
int dirsep;
{
char *p, *d, *pe, *se;
d = pe = se = 0;
for (p = pat; p && *p; p++)
{
if (extglob_pattern_p (p))
{
if (se == 0)
se = p + strlen (p) - 1;
pe = glob_patscan (p + 2, se, 0);
if (pe == 0)
continue;
else if (*pe == 0)
break;
p = pe - 1; /* will do increment above */
continue;
}
if (*p == dirsep)
d = p;
}
return d;
}
+76
View File
@@ -0,0 +1,76 @@
# This makefile for Readline library documentation is in -*- text -*- mode.
# Emacs likes it that way.
RM = rm -f
MAKEINFO = makeinfo
TEXI2DVI = texi2dvi
TEXI2HTML = texi2html
QUIETPS = #set this to -q to shut up dvips
DVIPS = dvips -D 300 $(QUIETPS) -o $@ # tricky
INSTALL_DATA = cp
infodir = /usr/local/info
RLSRC = rlman.texinfo rluser.texinfo rltech.texinfo
HISTSRC = hist.texinfo hsuser.texinfo hstech.texinfo
DVIOBJ = readline.dvi history.dvi
INFOOBJ = readline.info history.info
PSOBJ = readline.ps history.ps
HTMLOBJ = readline.html history.html
all: info dvi html ps
nodvi: info html
readline.dvi: $(RLSRC)
$(TEXI2DVI) rlman.texinfo
mv rlman.dvi readline.dvi
readline.info: $(RLSRC)
$(MAKEINFO) --no-split -o $@ rlman.texinfo
history.dvi: ${HISTSRC}
$(TEXI2DVI) hist.texinfo
mv hist.dvi history.dvi
history.info: ${HISTSRC}
$(MAKEINFO) --no-split -o $@ hist.texinfo
readline.ps: readline.dvi
$(RM) $@
$(DVIPS) readline.dvi
history.ps: history.dvi
$(RM) $@
$(DVIPS) history.dvi
readline.html: ${RLSRC}
$(TEXI2HTML) rlman.texinfo
sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman.html > readline.html
sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman_toc.html > readline_toc.html
$(RM) rlman.html rlman_toc.html
history.html: ${HISTSRC}
$(TEXI2HTML) hist.texinfo
sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist.html > history.html
sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist_toc.html > history_toc.html
$(RM) hist.html hist_toc.html
info: $(INFOOBJ)
dvi: $(DVIOBJ)
ps: $(PSOBJ)
html: $(HTMLOBJ)
clean:
$(RM) *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \
*.fns *.kys *.tps *.vrs *.o core
distclean: clean
mostlyclean: clean
maintainer-clean: clean
$(RM) *.dvi *.info *.info-* *.ps *.html
install: info
${INSTALL_DATA} readline.info $(infodir)/readline.info
${INSTALL_DATA} history.info $(infodir)/history.info
+1
View File
@@ -695,6 +695,7 @@ make_redirection (source, instruction, dest_and_filename, flags)
/* First do the common cases. */
temp->redirector = source;
temp->redirectee = dest_and_filename;
temp->here_doc_eof = 0;
temp->instruction = instruction;
temp->flags = 0;
temp->rflags = flags;
+894
View File
@@ -0,0 +1,894 @@
/* make_cmd.c -- Functions for making instances of the various
parser constructs. */
/* Copyright (C) 1989-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"
#include <stdio.h>
#include "bashtypes.h"
#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#include "filecntl.h"
#include "bashansi.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "bashintl.h"
#include "parser.h"
#include "syntax.h"
#include "command.h"
#include "general.h"
#include "error.h"
#include "flags.h"
#include "make_cmd.h"
#include "dispose_cmd.h"
#include "variables.h"
#include "subst.h"
#include "input.h"
#include "ocache.h"
#include "externs.h"
#if defined (JOB_CONTROL)
#include "jobs.h"
#endif
#include "shmbutil.h"
extern int line_number, current_command_line_count, parser_state;
extern int last_command_exit_value;
/* Object caching */
sh_obj_cache_t wdcache = {0, 0, 0};
sh_obj_cache_t wlcache = {0, 0, 0};
#define WDCACHESIZE 60
#define WLCACHESIZE 60
static COMMAND *make_for_or_select __P((enum command_type, WORD_DESC *, WORD_LIST *, COMMAND *, int));
#if defined (ARITH_FOR_COMMAND)
static WORD_LIST *make_arith_for_expr __P((char *));
#endif
static COMMAND *make_until_or_while __P((enum command_type, COMMAND *, COMMAND *));
void
cmd_init ()
{
ocache_create (wdcache, WORD_DESC, WDCACHESIZE);
ocache_create (wlcache, WORD_LIST, WLCACHESIZE);
}
WORD_DESC *
alloc_word_desc ()
{
WORD_DESC *temp;
ocache_alloc (wdcache, WORD_DESC, temp);
temp->flags = 0;
temp->word = 0;
return temp;
}
WORD_DESC *
make_bare_word (string)
const char *string;
{
WORD_DESC *temp;
temp = alloc_word_desc ();
if (*string)
temp->word = savestring (string);
else
{
temp->word = (char *)xmalloc (1);
temp->word[0] = '\0';
}
return (temp);
}
WORD_DESC *
make_word_flags (w, string)
WORD_DESC *w;
const char *string;
{
register int i;
size_t slen;
DECLARE_MBSTATE;
i = 0;
slen = strlen (string);
while (i < slen)
{
switch (string[i])
{
case '$':
w->flags |= W_HASDOLLAR;
break;
case '\\':
break; /* continue the loop */
case '\'':
case '`':
case '"':
w->flags |= W_QUOTED;
break;
}
ADVANCE_CHAR (string, slen, i);
}
return (w);
}
WORD_DESC *
make_word (string)
const char *string;
{
WORD_DESC *temp;
temp = make_bare_word (string);
return (make_word_flags (temp, string));
}
WORD_DESC *
make_word_from_token (token)
int token;
{
char tokenizer[2];
tokenizer[0] = token;
tokenizer[1] = '\0';
return (make_word (tokenizer));
}
WORD_LIST *
make_word_list (word, wlink)
WORD_DESC *word;
WORD_LIST *wlink;
{
WORD_LIST *temp;
ocache_alloc (wlcache, WORD_LIST, temp);
temp->word = word;
temp->next = wlink;
return (temp);
}
COMMAND *
make_command (type, pointer)
enum command_type type;
SIMPLE_COM *pointer;
{
COMMAND *temp;
temp = (COMMAND *)xmalloc (sizeof (COMMAND));
temp->type = type;
temp->value.Simple = pointer;
temp->value.Simple->flags = temp->flags = 0;
temp->redirects = (REDIRECT *)NULL;
return (temp);
}
COMMAND *
command_connect (com1, com2, connector)
COMMAND *com1, *com2;
int connector;
{
CONNECTION *temp;
temp = (CONNECTION *)xmalloc (sizeof (CONNECTION));
temp->connector = connector;
temp->first = com1;
temp->second = com2;
return (make_command (cm_connection, (SIMPLE_COM *)temp));
}
static COMMAND *
make_for_or_select (type, name, map_list, action, lineno)
enum command_type type;
WORD_DESC *name;
WORD_LIST *map_list;
COMMAND *action;
int lineno;
{
FOR_COM *temp;
temp = (FOR_COM *)xmalloc (sizeof (FOR_COM));
temp->flags = 0;
temp->name = name;
temp->line = lineno;
temp->map_list = map_list;
temp->action = action;
return (make_command (type, (SIMPLE_COM *)temp));
}
COMMAND *
make_for_command (name, map_list, action, lineno)
WORD_DESC *name;
WORD_LIST *map_list;
COMMAND *action;
int lineno;
{
return (make_for_or_select (cm_for, name, map_list, action, lineno));
}
COMMAND *
make_select_command (name, map_list, action, lineno)
WORD_DESC *name;
WORD_LIST *map_list;
COMMAND *action;
int lineno;
{
#if defined (SELECT_COMMAND)
return (make_for_or_select (cm_select, name, map_list, action, lineno));
#else
last_command_exit_value = 2;
return ((COMMAND *)NULL);
#endif
}
#if defined (ARITH_FOR_COMMAND)
static WORD_LIST *
make_arith_for_expr (s)
char *s;
{
WORD_LIST *result;
WORD_DESC *wd;
if (s == 0 || *s == '\0')
return ((WORD_LIST *)NULL);
wd = make_word (s);
wd->flags |= W_NOGLOB|W_NOSPLIT|W_QUOTED|W_DQUOTE; /* no word splitting or globbing */
#if defined (PROCESS_SUBSTITUTION)
wd->flags |= W_NOPROCSUB; /* no process substitution */
#endif
result = make_word_list (wd, (WORD_LIST *)NULL);
return result;
}
#endif
/* Note that this function calls dispose_words on EXPRS, since it doesn't
use the word list directly. We free it here rather than at the caller
because no other function in this file requires that the caller free
any arguments. */
COMMAND *
make_arith_for_command (exprs, action, lineno)
WORD_LIST *exprs;
COMMAND *action;
int lineno;
{
#if defined (ARITH_FOR_COMMAND)
ARITH_FOR_COM *temp;
WORD_LIST *init, *test, *step;
char *s, *t, *start;
int nsemi, i;
init = test = step = (WORD_LIST *)NULL;
/* Parse the string into the three component sub-expressions. */
start = t = s = exprs->word->word;
for (nsemi = 0; ;)
{
/* skip whitespace at the start of each sub-expression. */
while (whitespace (*s))
s++;
start = s;
/* skip to the semicolon or EOS */
i = skip_to_delim (start, 0, ";", SD_NOJMP|SD_NOPROCSUB);
s = start + i;
t = (i > 0) ? substring (start, 0, i) : (char *)NULL;
nsemi++;
switch (nsemi)
{
case 1:
init = make_arith_for_expr (t);
break;
case 2:
test = make_arith_for_expr (t);
break;
case 3:
step = make_arith_for_expr (t);
break;
}
FREE (t);
if (*s == '\0')
break;
s++; /* skip over semicolon */
}
if (nsemi != 3)
{
if (nsemi < 3)
parser_error (lineno, _("syntax error: arithmetic expression required"));
else
parser_error (lineno, _("syntax error: `;' unexpected"));
parser_error (lineno, _("syntax error: `((%s))'"), exprs->word->word);
free (init);
free (test);
free (step);
last_command_exit_value = 2;
return ((COMMAND *)NULL);
}
temp = (ARITH_FOR_COM *)xmalloc (sizeof (ARITH_FOR_COM));
temp->flags = 0;
temp->line = lineno;
temp->init = init ? init : make_arith_for_expr ("1");
temp->test = test ? test : make_arith_for_expr ("1");
temp->step = step ? step : make_arith_for_expr ("1");
temp->action = action;
dispose_words (exprs);
return (make_command (cm_arith_for, (SIMPLE_COM *)temp));
#else
dispose_words (exprs);
last_command_exit_value = 2;
return ((COMMAND *)NULL);
#endif /* ARITH_FOR_COMMAND */
}
COMMAND *
make_group_command (command)
COMMAND *command;
{
GROUP_COM *temp;
temp = (GROUP_COM *)xmalloc (sizeof (GROUP_COM));
temp->command = command;
return (make_command (cm_group, (SIMPLE_COM *)temp));
}
COMMAND *
make_case_command (word, clauses, lineno)
WORD_DESC *word;
PATTERN_LIST *clauses;
int lineno;
{
CASE_COM *temp;
temp = (CASE_COM *)xmalloc (sizeof (CASE_COM));
temp->flags = 0;
temp->line = lineno;
temp->word = word;
temp->clauses = REVERSE_LIST (clauses, PATTERN_LIST *);
return (make_command (cm_case, (SIMPLE_COM *)temp));
}
PATTERN_LIST *
make_pattern_list (patterns, action)
WORD_LIST *patterns;
COMMAND *action;
{
PATTERN_LIST *temp;
temp = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST));
temp->patterns = REVERSE_LIST (patterns, WORD_LIST *);
temp->action = action;
temp->next = NULL;
temp->flags = 0;
return (temp);
}
COMMAND *
make_if_command (test, true_case, false_case)
COMMAND *test, *true_case, *false_case;
{
IF_COM *temp;
temp = (IF_COM *)xmalloc (sizeof (IF_COM));
temp->flags = 0;
temp->test = test;
temp->true_case = true_case;
temp->false_case = false_case;
return (make_command (cm_if, (SIMPLE_COM *)temp));
}
static COMMAND *
make_until_or_while (which, test, action)
enum command_type which;
COMMAND *test, *action;
{
WHILE_COM *temp;
temp = (WHILE_COM *)xmalloc (sizeof (WHILE_COM));
temp->flags = 0;
temp->test = test;
temp->action = action;
return (make_command (which, (SIMPLE_COM *)temp));
}
COMMAND *
make_while_command (test, action)
COMMAND *test, *action;
{
return (make_until_or_while (cm_while, test, action));
}
COMMAND *
make_until_command (test, action)
COMMAND *test, *action;
{
return (make_until_or_while (cm_until, test, action));
}
COMMAND *
make_arith_command (exp)
WORD_LIST *exp;
{
#if defined (DPAREN_ARITHMETIC)
COMMAND *command;
ARITH_COM *temp;
command = (COMMAND *)xmalloc (sizeof (COMMAND));
command->value.Arith = temp = (ARITH_COM *)xmalloc (sizeof (ARITH_COM));
temp->flags = 0;
temp->line = line_number;
temp->exp = exp;
command->type = cm_arith;
command->redirects = (REDIRECT *)NULL;
command->flags = 0;
return (command);
#else
last_command_exit_value = 2;
return ((COMMAND *)NULL);
#endif
}
#if defined (COND_COMMAND)
struct cond_com *
make_cond_node (type, op, left, right)
int type;
WORD_DESC *op;
struct cond_com *left, *right;
{
COND_COM *temp;
temp = (COND_COM *)xmalloc (sizeof (COND_COM));
temp->flags = 0;
temp->line = line_number;
temp->type = type;
temp->op = op;
temp->left = left;
temp->right = right;
return (temp);
}
#endif
COMMAND *
make_cond_command (cond_node)
COND_COM *cond_node;
{
#if defined (COND_COMMAND)
COMMAND *command;
command = (COMMAND *)xmalloc (sizeof (COMMAND));
command->value.Cond = cond_node;
command->type = cm_cond;
command->redirects = (REDIRECT *)NULL;
command->flags = 0;
command->line = cond_node ? cond_node->line : 0;
return (command);
#else
last_command_exit_value = 2;
return ((COMMAND *)NULL);
#endif
}
COMMAND *
make_bare_simple_command ()
{
COMMAND *command;
SIMPLE_COM *temp;
command = (COMMAND *)xmalloc (sizeof (COMMAND));
command->value.Simple = temp = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM));
temp->flags = 0;
temp->line = line_number;
temp->words = (WORD_LIST *)NULL;
temp->redirects = (REDIRECT *)NULL;
command->type = cm_simple;
command->redirects = (REDIRECT *)NULL;
command->flags = 0;
return (command);
}
/* Return a command which is the connection of the word or redirection
in ELEMENT, and the command * or NULL in COMMAND. */
COMMAND *
make_simple_command (element, command)
ELEMENT element;
COMMAND *command;
{
/* If we are starting from scratch, then make the initial command
structure. Also note that we have to fill in all the slots, since
malloc doesn't return zeroed space. */
if (command == 0)
{
command = make_bare_simple_command ();
parser_state |= PST_REDIRLIST;
}
if (element.word)
{
command->value.Simple->words = make_word_list (element.word, command->value.Simple->words);
parser_state &= ~PST_REDIRLIST;
}
else if (element.redirect)
{
REDIRECT *r = element.redirect;
/* Due to the way <> is implemented, there may be more than a single
redirection in element.redirect. We just follow the chain as far
as it goes, and hook onto the end. */
while (r->next)
r = r->next;
r->next = command->value.Simple->redirects;
command->value.Simple->redirects = element.redirect;
}
return (command);
}
/* Because we are Bourne compatible, we read the input for this
<< or <<- redirection now, from wherever input is coming from.
We store the input read into a WORD_DESC. Replace the text of
the redirectee.word with the new input text. If <<- is on,
then remove leading TABS from each line. */
void
make_here_document (temp, lineno)
REDIRECT *temp;
int lineno;
{
int kill_leading, redir_len;
char *redir_word, *document, *full_line;
int document_index, document_size, delim_unquoted;
if (temp->instruction != r_deblank_reading_until &&
temp->instruction != r_reading_until)
{
internal_error (_("make_here_document: bad instruction type %d"), temp->instruction);
return;
}
kill_leading = temp->instruction == r_deblank_reading_until;
document = (char *)NULL;
document_index = document_size = 0;
/* Quote removal is the only expansion performed on the delimiter
for here documents, making it an extremely special case. */
redir_word = string_quote_removal (temp->redirectee.filename->word, 0);
/* redirection_expand will return NULL if the expansion results in
multiple words or no words. Check for that here, and just abort
this here document if it does. */
if (redir_word)
redir_len = strlen (redir_word);
else
{
temp->here_doc_eof = (char *)xmalloc (1);
temp->here_doc_eof[0] = '\0';
goto document_done;
}
free (temp->redirectee.filename->word);
temp->here_doc_eof = redir_word;
/* Read lines from wherever lines are coming from.
For each line read, if kill_leading, then kill the
leading tab characters.
If the line matches redir_word exactly, then we have
manufactured the document. Otherwise, add the line to the
list of lines in the document. */
/* If the here-document delimiter was quoted, the lines should
be read verbatim from the input. If it was not quoted, we
need to perform backslash-quoted newline removal. */
delim_unquoted = (temp->redirectee.filename->flags & W_QUOTED) == 0;
while (full_line = read_secondary_line (delim_unquoted))
{
register char *line;
int len;
line = full_line;
line_number++;
/* If set -v is in effect, echo the line read. read_secondary_line/
read_a_line leaves the newline at the end, so don't print another. */
if (echo_input_at_read)
fprintf (stderr, "%s", line);
if (kill_leading && *line)
{
/* Hack: To be compatible with some Bourne shells, we
check the word before stripping the whitespace. This
is a hack, though. */
if (STREQN (line, redir_word, redir_len) && line[redir_len] == '\n')
goto document_done;
while (*line == '\t')
line++;
}
if (*line == 0)
continue;
if (STREQN (line, redir_word, redir_len) && line[redir_len] == '\n')
goto document_done;
len = strlen (line);
if (len + document_index >= document_size)
{
document_size = document_size ? 2 * (document_size + len) : len + 2;
document = (char *)xrealloc (document, document_size);
}
/* len is guaranteed to be > 0 because of the check for line
being an empty string before the call to strlen. */
FASTCOPY (line, document + document_index, len);
document_index += len;
}
if (full_line == 0)
internal_warning (_("here-document at line %d delimited by end-of-file (wanted `%s')"), lineno, redir_word);
document_done:
if (document)
document[document_index] = '\0';
else
{
document = (char *)xmalloc (1);
document[0] = '\0';
}
temp->redirectee.filename->word = document;
}
/* Generate a REDIRECT from SOURCE, DEST, and INSTRUCTION.
INSTRUCTION is the instruction type, SOURCE is a file descriptor,
and DEST is a file descriptor or a WORD_DESC *. */
REDIRECT *
make_redirection (source, instruction, dest_and_filename, flags)
REDIRECTEE source;
enum r_instruction instruction;
REDIRECTEE dest_and_filename;
int flags;
{
REDIRECT *temp;
WORD_DESC *w;
int wlen;
intmax_t lfd;
temp = (REDIRECT *)xmalloc (sizeof (REDIRECT));
/* First do the common cases. */
temp->redirector = source;
temp->redirectee = dest_and_filename;
temp->instruction = instruction;
temp->flags = 0;
temp->rflags = flags;
temp->next = (REDIRECT *)NULL;
switch (instruction)
{
case r_output_direction: /* >foo */
case r_output_force: /* >| foo */
case r_err_and_out: /* &>filename */
temp->flags = O_TRUNC | O_WRONLY | O_CREAT;
break;
case r_appending_to: /* >>foo */
case r_append_err_and_out: /* &>> filename */
temp->flags = O_APPEND | O_WRONLY | O_CREAT;
break;
case r_input_direction: /* <foo */
case r_inputa_direction: /* foo & makes this. */
temp->flags = O_RDONLY;
break;
case r_input_output: /* <>foo */
temp->flags = O_RDWR | O_CREAT;
break;
case r_deblank_reading_until: /* <<-foo */
case r_reading_until: /* << foo */
case r_reading_string: /* <<< foo */
case r_close_this: /* <&- */
case r_duplicating_input: /* 1<&2 */
case r_duplicating_output: /* 1>&2 */
break;
/* the parser doesn't pass these. */
case r_move_input: /* 1<&2- */
case r_move_output: /* 1>&2- */
case r_move_input_word: /* 1<&$foo- */
case r_move_output_word: /* 1>&$foo- */
break;
/* The way the lexer works we have to do this here. */
case r_duplicating_input_word: /* 1<&$foo */
case r_duplicating_output_word: /* 1>&$foo */
w = dest_and_filename.filename;
wlen = strlen (w->word) - 1;
if (w->word[wlen] == '-') /* Yuck */
{
w->word[wlen] = '\0';
if (all_digits (w->word) && legal_number (w->word, &lfd) && lfd == (int)lfd)
{
dispose_word (w);
temp->instruction = (instruction == r_duplicating_input_word) ? r_move_input : r_move_output;
temp->redirectee.dest = lfd;
}
else
temp->instruction = (instruction == r_duplicating_input_word) ? r_move_input_word : r_move_output_word;
}
break;
default:
programming_error (_("make_redirection: redirection instruction `%d' out of range"), instruction);
abort ();
break;
}
return (temp);
}
COMMAND *
make_function_def (name, command, lineno, lstart)
WORD_DESC *name;
COMMAND *command;
int lineno, lstart;
{
FUNCTION_DEF *temp;
#if defined (ARRAY_VARS)
SHELL_VAR *bash_source_v;
ARRAY *bash_source_a;
#endif
temp = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF));
temp->command = command;
temp->name = name;
temp->line = lineno;
temp->flags = 0;
command->line = lstart;
/* Information used primarily for debugging. */
temp->source_file = 0;
#if defined (ARRAY_VARS)
GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
if (bash_source_a && array_num_elements (bash_source_a) > 0)
temp->source_file = array_reference (bash_source_a, 0);
#endif
#if defined (DEBUGGER)
bind_function_def (name->word, temp);
#endif
temp->source_file = temp->source_file ? savestring (temp->source_file) : 0;
return (make_command (cm_function_def, (SIMPLE_COM *)temp));
}
COMMAND *
make_subshell_command (command)
COMMAND *command;
{
SUBSHELL_COM *temp;
temp = (SUBSHELL_COM *)xmalloc (sizeof (SUBSHELL_COM));
temp->command = command;
temp->flags = CMD_WANT_SUBSHELL;
return (make_command (cm_subshell, (SIMPLE_COM *)temp));
}
COMMAND *
make_coproc_command (name, command)
char *name;
COMMAND *command;
{
COPROC_COM *temp;
temp = (COPROC_COM *)xmalloc (sizeof (COPROC_COM));
temp->name = savestring (name);
temp->command = command;
temp->flags = CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL;
return (make_command (cm_coproc, (SIMPLE_COM *)temp));
}
/* Reverse the word list and redirection list in the simple command
has just been parsed. It seems simpler to do this here the one
time then by any other method that I can think of. */
COMMAND *
clean_simple_command (command)
COMMAND *command;
{
if (command->type != cm_simple)
command_error ("clean_simple_command", CMDERR_BADTYPE, command->type, 0);
else
{
command->value.Simple->words =
REVERSE_LIST (command->value.Simple->words, WORD_LIST *);
command->value.Simple->redirects =
REVERSE_LIST (command->value.Simple->redirects, REDIRECT *);
}
parser_state &= ~PST_REDIRLIST;
return (command);
}
/* The Yacc grammar productions have a problem, in that they take a
list followed by an ampersand (`&') and do a simple command connection,
making the entire list effectively asynchronous, instead of just
the last command. This means that when the list is executed, all
the commands have stdin set to /dev/null when job control is not
active, instead of just the last. This is wrong, and needs fixing
up. This function takes the `&' and applies it to the last command
in the list. This is done only for lists connected by `;'; it makes
`;' bind `tighter' than `&'. */
COMMAND *
connect_async_list (command, command2, connector)
COMMAND *command, *command2;
int connector;
{
COMMAND *t, *t1, *t2;
t1 = command;
t = command->value.Connection->second;
if (!t || (command->flags & CMD_WANT_SUBSHELL) ||
command->value.Connection->connector != ';')
{
t = command_connect (command, command2, connector);
return t;
}
/* This is just defensive programming. The Yacc precedence rules
will generally hand this function a command where t points directly
to the command we want (e.g. given a ; b ; c ; d &, t1 will point
to the `a ; b ; c' list and t will be the `d'). We only want to do
this if the list is not being executed as a unit in the background
with `( ... )', so we have to check for CMD_WANT_SUBSHELL. That's
the only way to tell. */
while (((t->flags & CMD_WANT_SUBSHELL) == 0) && t->type == cm_connection &&
t->value.Connection->connector == ';')
{
t1 = t;
t = t->value.Connection->second;
}
/* Now we have t pointing to the last command in the list, and
t1->value.Connection->second == t. */
t2 = command_connect (t, command2, connector);
t1->value.Connection->second = t2;
return command;
}
+1 -1
View File
@@ -959,7 +959,7 @@ describe_pid (pid)
fprintf (stderr, "%ld\n", (long) pid);
}
void
int
freeze_jobs_list ()
{
}
+30 -8
View File
@@ -168,6 +168,9 @@ static char *read_a_line __P((int));
static int reserved_word_acceptable __P((int));
static int yylex __P((void));
static void push_heredoc __P((REDIRECT *));
static char *mk_alexpansion __P((char *));
static int alias_expand_token __P((char *));
static int time_command_acceptable __P((void));
static int special_case_tokens __P((char *));
@@ -265,7 +268,9 @@ int parser_state;
/* Variables to manage the task of reading here documents, because we need to
defer the reading until after a complete command has been collected. */
static REDIRECT *redir_stack[10];
#define HEREDOC_MAX 16
static REDIRECT *redir_stack[HEREDOC_MAX];
int need_here_doc;
/* Where shell input comes from. History expansion is performed on each
@@ -307,7 +312,7 @@ static int global_extglob;
or `for WORD' begins. This is a nested command maximum, since the array
index is decremented after a case, select, or for command is parsed. */
#define MAX_CASE_NEST 128
static int word_lineno[MAX_CASE_NEST];
static int word_lineno[MAX_CASE_NEST+1];
static int word_top = -1;
/* If non-zero, it is the token that we want read_token to return
@@ -520,42 +525,42 @@ redirection: '>' WORD
source.dest = 0;
redir.filename = $2;
$$ = make_redirection (source, r_reading_until, redir, 0);
redir_stack[need_here_doc++] = $$;
push_heredoc ($$);
}
| NUMBER LESS_LESS WORD
{
source.dest = $1;
redir.filename = $3;
$$ = make_redirection (source, r_reading_until, redir, 0);
redir_stack[need_here_doc++] = $$;
push_heredoc ($$);
}
| REDIR_WORD LESS_LESS WORD
{
source.filename = $1;
redir.filename = $3;
$$ = make_redirection (source, r_reading_until, redir, REDIR_VARASSIGN);
redir_stack[need_here_doc++] = $$;
push_heredoc ($$);
}
| LESS_LESS_MINUS WORD
{
source.dest = 0;
redir.filename = $2;
$$ = make_redirection (source, r_deblank_reading_until, redir, 0);
redir_stack[need_here_doc++] = $$;
push_heredoc ($$);
}
| NUMBER LESS_LESS_MINUS WORD
{
source.dest = $1;
redir.filename = $3;
$$ = make_redirection (source, r_deblank_reading_until, redir, 0);
redir_stack[need_here_doc++] = $$;
push_heredoc ($$);
}
| REDIR_WORD LESS_LESS_MINUS WORD
{
source.filename = $1;
redir.filename = $3;
$$ = make_redirection (source, r_deblank_reading_until, redir, REDIR_VARASSIGN);
redir_stack[need_here_doc++] = $$;
push_heredoc ($$);
}
| LESS_LESS_LESS WORD
{
@@ -2636,6 +2641,21 @@ yylex ()
which allow ESAC to be the next one read. */
static int esacs_needed_count;
static void
push_heredoc (r)
REDIRECT *r;
{
if (need_here_doc >= HEREDOC_MAX)
{
last_command_exit_value = EX_BADUSAGE;
need_here_doc = 0;
report_syntax_error (_("maximum here-document count exceeded"));
reset_parser ();
exit_shell (last_command_exit_value);
}
redir_stack[need_here_doc++] = r;
}
void
gather_here_documents ()
{
@@ -2958,6 +2978,8 @@ reset_parser ()
FREE (word_desc_to_read);
word_desc_to_read = (WORD_DESC *)NULL;
eol_ungetc_lookahead = 0;
current_token = '\n'; /* XXX */
last_read_token = '\n';
token_to_read = '\n';
+1 -1
View File
@@ -25,6 +25,6 @@
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
looks for to find the patch level (for the sccs version string). */
#define PATCHLEVEL 24
#define PATCHLEVEL 25
#endif /* _PATCHLEVEL_H_ */
+1 -1
View File
@@ -1,4 +1,4 @@
BUILD_DIR=/usr/local/build/chet/bash/bash-current
BUILD_DIR=/usr/local/build/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
+9
View File
@@ -0,0 +1,9 @@
BUILD_DIR=/usr/local/build/chet/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
export THIS_SH PATH
rm -f /tmp/xx
/bin/sh "$@"
+50
View File
@@ -0,0 +1,50 @@
:; ./shx
sh:
<&$fd ok
nlbq Mon Aug 3 02:45:00 EDT 1992
bang geoff
quote 712824302
setbq defmsgid=<1992Aug3.024502.6176@host>
bgwait sleep done... wait 6187
bash:
<&$fd ok
nlbq Mon Aug 3 02:45:09 EDT 1992
bang geoff
quote 712824311
setbq defmsgid=<1992Aug3.024512.6212@host>
bgwait sleep done... wait 6223
ash:
<&$fd shx1: 4: Syntax error: Bad fd number
nlbq Mon Aug 3 02:45:19 EDT 1992
bang geoff
quote getdate: `"now"' not a valid date
setbq defmsgid=<1992Aug3.` echo 024521
bgwait sleep done... wait 6241
ksh:
<&$fd ok
nlbq ./shx: 6248 Memory fault - core dumped
bang geoff
quote getdate: `"now"' not a valid date
setbq defmsgid=<1992Aug3.024530.6257@host>
bgwait no such job: 6265
wait 6265
sleep done...
zsh:
<&$fd ok
nlbq Mon Aug 3 02:45:36 EDT 1992
bang shx3: event not found: /s/ [4]
quote 712824337
setbq defmsgid=<..6290@host>
bgwait shx7: unmatched " [9]
sleep done...
:;
+10
View File
@@ -0,0 +1,10 @@
#! /bin/sh
for cmd in sh bash ash ksh zsh
do
echo
echo $cmd:
for demo in shx?
do
$cmd $demo
done
done
+2
View File
@@ -857,7 +857,9 @@ run_exit_trap ()
retval = trap_saved_exit_value;
running_trap = 0;
#if defined (ARRAY_VARS)
array_dispose (ps);
#endif
return retval;
}
+1275
View File
File diff suppressed because it is too large Load Diff
+63 -23
View File
@@ -1,6 +1,6 @@
/* variables.c -- Functions for hacking shell variables. */
/* Copyright (C) 1987-2013 Free Software Foundation, Inc.
/* Copyright (C) 1987-2014 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -83,6 +83,11 @@
#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0')
#define BASHFUNC_PREFIX "BASH_FUNC_"
#define BASHFUNC_PREFLEN 10 /* == strlen(BASHFUNC_PREFIX */
#define BASHFUNC_SUFFIX "%%"
#define BASHFUNC_SUFFLEN 2 /* == strlen(BASHFUNC_SUFFIX) */
/* flags for find_variable_internal */
#define FV_FORCETEMPENV 0x01
@@ -284,7 +289,7 @@ static void push_temp_var __P((PTR_T));
static void propagate_temp_var __P((PTR_T));
static void dispose_temporary_env __P((sh_free_func_t *));
static inline char *mk_env_string __P((const char *, const char *));
static inline char *mk_env_string __P((const char *, const char *, int));
static char **make_env_array_from_var_list __P((SHELL_VAR **));
static char **make_var_export_array __P((VAR_CONTEXT *));
static char **make_func_export_array __P((void));
@@ -354,22 +359,33 @@ initialize_shell_variables (env, privmode)
/* If exported function, define it now. Don't import functions from
the environment in privileged mode. */
if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4))
if (privmode == 0 && read_but_dont_execute == 0 &&
STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN) &&
STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN) &&
STREQN ("() {", string, 4))
{
string_length = strlen (string);
temp_string = (char *)xmalloc (3 + string_length + char_index);
size_t namelen;
char *tname; /* desired imported function name */
strcpy (temp_string, name);
temp_string[char_index] = ' ';
strcpy (temp_string + char_index + 1, string);
namelen = char_index - BASHFUNC_PREFLEN - BASHFUNC_SUFFLEN;
tname = name + BASHFUNC_PREFLEN; /* start of func name */
tname[namelen] = '\0'; /* now tname == func name */
string_length = strlen (string);
temp_string = (char *)xmalloc (namelen + string_length + 2);
memcpy (temp_string, tname, namelen);
temp_string[namelen] = ' ';
memcpy (temp_string + namelen + 1, string, string_length + 1);
/* Don't import function names that are invalid identifiers from the
environment, though we still allow them to be defined as shell
variables. */
if (legal_identifier (name))
parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname)))
parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
if (temp_var = find_function (name))
if (temp_var = find_function (tname))
{
VSETATTR (temp_var, (att_exported|att_imported));
array_needs_making = 1;
@@ -382,8 +398,11 @@ initialize_shell_variables (env, privmode)
array_needs_making = 1;
}
last_command_exit_value = 1;
report_error (_("error importing function definition for `%s'"), name);
report_error (_("error importing function definition for `%s'"), tname);
}
/* Restore original suffix */
tname[namelen] = BASHFUNC_SUFFIX[0];
}
#if defined (ARRAY_VARS)
# if ARRAY_EXPORT
@@ -3021,7 +3040,7 @@ assign_in_env (word, flags)
var->context = variable_context; /* XXX */
INVALIDATE_EXPORTSTR (var);
var->exportstr = mk_env_string (name, value);
var->exportstr = mk_env_string (name, value, 0);
array_needs_making = 1;
@@ -3919,21 +3938,42 @@ merge_temporary_env ()
/* **************************************************************** */
static inline char *
mk_env_string (name, value)
mk_env_string (name, value, isfunc)
const char *name, *value;
int isfunc;
{
int name_len, value_len;
char *p;
size_t name_len, value_len;
char *p, *q;
name_len = strlen (name);
value_len = STRLEN (value);
p = (char *)xmalloc (2 + name_len + value_len);
strcpy (p, name);
p[name_len] = '=';
if (value && *value)
strcpy (p + name_len + 1, value);
/* If we are exporting a shell function, construct the encoded function
name. */
if (isfunc && value)
{
p = (char *)xmalloc (BASHFUNC_PREFLEN + name_len + BASHFUNC_SUFFLEN + value_len + 2);
q = p;
memcpy (q, BASHFUNC_PREFIX, BASHFUNC_PREFLEN);
q += BASHFUNC_PREFLEN;
memcpy (q, name, name_len);
q += name_len;
memcpy (q, BASHFUNC_SUFFIX, BASHFUNC_SUFFLEN);
q += BASHFUNC_SUFFLEN;
}
else
p[name_len + 1] = '\0';
{
p = (char *)xmalloc (2 + name_len + value_len);
memcpy (p, name, name_len);
q = p + name_len;
}
q[0] = '=';
if (value && *value)
memcpy (q + 1, value, value_len + 1);
else
q[1] = '\0';
return (p);
}
@@ -4019,7 +4059,7 @@ make_env_array_from_var_list (vars)
/* Gee, I'd like to get away with not using savestring() if we're
using the cached exportstr... */
list[list_index] = USE_EXPORTSTR ? savestring (value)
: mk_env_string (var->name, value);
: mk_env_string (var->name, value, function_p (var));
if (USE_EXPORTSTR == 0)
SAVE_EXPORTSTR (var, list[list_index]);
+5432
View File
File diff suppressed because it is too large Load Diff