commit bash-20060727 snapshot

This commit is contained in:
Chet Ramey
2011-12-03 22:51:04 -05:00
parent 9697d2dc75
commit 5cef52a763
76 changed files with 7162 additions and 239 deletions
+15 -1
View File
@@ -13516,7 +13516,7 @@ lib/readline/display.c
7/5
---
builtins/printf.def
- add echo's write error handling to printf. Suggested by
- add more of echo's write error handling to printf. Suggested by
martin.wilck@fujitsu-siemens.com
7/7
@@ -13566,3 +13566,17 @@ lib/malloc/{stats,table}.h
lib/termcap/{termcap,tparam}.c
- include <string.h> and provide macro replacement for bcopy if
necessary
7/27
----
lib/readline/histexpand.c
- add support for `<<<' here-string redirection operator to
history_tokenize_word. Bug reported by agriffis@gentoo.org
externs.h
- don't add prototype for strerror() if HAVE_STRERROR defined
7/29
----
subst.c
- in list_string, use `string' instead of `s' -- s is not initialized
+14 -1
View File
@@ -13516,7 +13516,7 @@ lib/readline/display.c
7/5
---
builtins/printf.def
- add echo's write error handling to printf. Suggested by
- add more of echo's write error handling to printf. Suggested by
martin.wilck@fujitsu-siemens.com
7/7
@@ -13562,3 +13562,16 @@ lib/readline/display.c
----
lib/malloc/{stats,table}.h
- include <string.h> for prototypes for memset, strlen
lib/termcap/{termcap,tparam}.c
- include <string.h> and provide macro replacement for bcopy if
necessary
7/27
----
lib/readline/histexpand.c
- add support for `<<<' here-string redirection operator to
history_tokenize_word. Bug reported by agriffis@gentoo.org
externs.h
- don't add prototype for strerror() if HAVE_STRERROR defined
+5 -2
View File
@@ -147,8 +147,11 @@ LDFLAGS_FOR_BUILD = $(LDFLAGS)
INCLUDES = -I. @RL_INCLUDE@ -I$(srcdir) -I$(BASHINCDIR) -I$(LIBSRC) $(INTL_INC)
GCC_LINT_FLAGS = -Wall -Wshadow -Wpointer-arith -Wcast-qual \
-Wcast-align -Wstrict-prototypes -Wconversion \
# Maybe add: -Wextra
GCC_LINT_FLAGS = -O -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wno-parentheses \
-Wcast-align -Wstrict-prototypes -Wconversion -Wformat \
-Wformat-nonliteral -Wmissing-braces -Wuninitialized \
-Wmissing-declarations -Winline \
-Wmissing-prototypes -Wtraditional -Wredundant-decls -pedantic
GCC_LINT_CFLAGS = $(BASE_CCFLAGS) $(CPPFLAGS) $(GCC_LINT_FLAGS)
+7 -4
View File
@@ -147,8 +147,11 @@ LDFLAGS_FOR_BUILD = $(LDFLAGS)
INCLUDES = -I. @RL_INCLUDE@ -I$(srcdir) -I$(BASHINCDIR) -I$(LIBSRC) $(INTL_INC)
GCC_LINT_FLAGS = -Wall -Wshadow -Wpointer-arith -Wcast-qual \
-Wcast-align -Wstrict-prototypes -Wconversion \
# Maybe add: -Wextra
GCC_LINT_FLAGS = -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wno-parentheses \
-Wcast-align -Wstrict-prototypes -Wconversion -Wformat \
-Wformat-nonliteral -Wmissing-braces -Wuninitialized \
-Wmissing-declarations -Winline \
-Wmissing-prototypes -Wtraditional -Wredundant-decls -pedantic
GCC_LINT_CFLAGS = $(BASE_CCFLAGS) $(CPPFLAGS) $(GCC_LINT_FLAGS)
@@ -201,7 +204,7 @@ SHLIB_SOURCE = ${SH_LIBSRC}/clktck.c ${SH_LIBSRC}/getcwd.c \
${SH_LIBSRC}/memset.c ${SH_LIBSRC}/xstrchr.c \
${SH_LIBSRC}/zcatfd.c ${SH_LIBSRC}/shmatch.c \
${SH_LIBSRC}/strnlen.c ${SH_LIBSRC}/winsize.c \
${SH_LIBSRC}/shaccess.c
${SH_LIBSRC}/eaccess.c ${SH_LIBSRC}/wcsdup.c
SHLIB_LIB = -lsh
SHLIB_LIBNAME = libsh.a
@@ -499,7 +502,7 @@ CREATED_SUPPORT = signames.h recho$(EXEEXT) zecho$(EXEEXT) printenv$(EXEEXT) \
tests/recho$(EXEEXT) tests/zecho$(EXEEXT) \
tests/printenv$(EXEEXT) mksignames$(EXEEXT) lsignames.h \
mksyntax${EXEEXT} syntax.c $(VERSPROG) $(VERSOBJ) \
buildversion.o mksignames.o signames.o
buildversion.o mksignames.o signames.o buildsignames.o
CREATED_CONFIGURE = config.h config.cache config.status config.log \
stamp-h po/POTFILES
CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \
-1
View File
@@ -273,7 +273,6 @@ expand_compound_array_assignment (value, flags)
WORD_LIST *list, *nlist;
char *val;
int ni;
arrayind_t ind, last_ind;
/* I don't believe this condition is ever true any more. */
if (*value == '(') /*)*/
+5 -2
View File
@@ -1461,7 +1461,9 @@ command_word_completion_function (hint_text, state)
else
{
int match, freetemp;
char *temp;
#if 0
char *temp; /* shadows previous declaration */
#endif
if (absolute_program (hint))
{
@@ -1760,8 +1762,9 @@ bash_servicename_completion_function (text, state)
if (snamelen == 0 || (STREQN (sname, srvent->s_name, snamelen)))
break;
/* Not primary, check aliases */
for (alist = srvent->s_aliases; aentry = *alist; alist++)
for (alist = srvent->s_aliases; *alist; alist++)
{
aentry = *alist;
if (STREQN (sname, aentry, snamelen))
{
afound = 1;
+3 -2
View File
@@ -1254,7 +1254,6 @@ command_word_completion_function (hint_text, state)
mapping_over = searching_path = 0;
hint_is_dir = CMD_IS_DIR (hint_text);
val = (char *)NULL;
temp = rl_variable_value ("completion-ignore-case");
@@ -1462,7 +1461,9 @@ command_word_completion_function (hint_text, state)
else
{
int match, freetemp;
char *temp;
#if 0
char *temp; /* shadows previous declaration */
#endif
if (absolute_program (hint))
{
-1
View File
@@ -76,7 +76,6 @@ caller_builtin (list)
SHELL_VAR *funcname_v, *bash_source_v, *bash_lineno_v;
ARRAY *funcname_a, *bash_source_a, *bash_lineno_a;
char *funcname_s, *source_s, *lineno_s;
ARRAY_ELEMENT *ae;
intmax_t num;
GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a);
+1
View File
@@ -60,6 +60,7 @@ extern char *bash_getcwd_errstr;
static int bindpwd __P((int));
static void setpwd __P((char *));
static char *resetpwd __P((char *));
static int change_to_directory __P((char *, int));
static char *cdspell __P((char *));
+525
View File
@@ -0,0 +1,525 @@
This file is cd.def, from which is created cd.c. It implements the
builtins "cd" and "pwd" in Bash.
Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
$PRODUCES cd.c
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashtypes.h"
#include "posixdir.h"
#include "posixstat.h"
#ifndef _MINIX
#include <sys/param.h>
#endif
#include <stdio.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include <errno.h>
#include <tilde/tilde.h>
#include "../shell.h"
#include "../flags.h"
#include "maxpath.h"
#include "common.h"
#include "bashgetopt.h"
#if !defined (errno)
extern int errno;
#endif /* !errno */
extern int posixly_correct;
extern int array_needs_making;
extern char *bash_getcwd_errstr;
static int bindpwd __P((int));
static void setpwd __P((char *));
static int change_to_directory __P((char *, int));
static char *cdspell __P((char *));
/* Change this to 1 to get cd spelling correction by default. */
int cdspelling = 0;
int cdable_vars;
$BUILTIN cd
$FUNCTION cd_builtin
$SHORT_DOC cd [-L|-P] [dir]
Change the current directory to DIR. The variable $HOME is the
default DIR. The variable CDPATH defines the search path for
the directory containing DIR. Alternative directory names in CDPATH
are separated by a colon (:). A null directory name is the same as
the current directory, i.e. `.'. If DIR begins with a slash (/),
then CDPATH is not used. If the directory is not found, and the
shell option `cdable_vars' is set, then try the word as a variable
name. If that variable has a value, then cd to the value of that
variable. The -P option says to use the physical directory structure
instead of following symbolic links; the -L option forces symbolic links
to be followed.
$END
/* Just set $PWD, don't change OLDPWD. Used by `pwd -P' in posix mode. */
static void
setpwd (dirname)
char *dirname;
{
int old_anm;
SHELL_VAR *tvar;
old_anm = array_needs_making;
tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
if (old_anm == 0 && array_needs_making && exported_p (tvar))
{
update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
array_needs_making = 0;
}
}
static int
bindpwd (no_symlinks)
int no_symlinks;
{
char *dirname, *pwdvar;
int old_anm;
SHELL_VAR *tvar;
#define tcwd the_current_working_directory
dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
: get_working_directory ("cd");
#undef tcwd
old_anm = array_needs_making;
pwdvar = get_string_value ("PWD");
tvar = bind_variable ("OLDPWD", pwdvar, 0);
if (old_anm == 0 && array_needs_making && exported_p (tvar))
{
update_export_env_inplace ("OLDPWD=", 7, pwdvar);
array_needs_making = 0;
}
setpwd (dirname);
if (dirname && dirname != the_current_working_directory)
free (dirname);
return (EXECUTION_SUCCESS);
}
/* Call get_working_directory to reset the value of
the_current_working_directory () */
static char *
resetpwd (caller)
char *caller;
{
char *tdir;
FREE (the_current_working_directory);
the_current_working_directory = (char *)NULL;
tdir = get_working_directory (caller);
return (tdir);
}
#define LCD_DOVARS 0x001
#define LCD_DOSPELL 0x002
#define LCD_PRINTPATH 0x004
#define LCD_FREEDIRNAME 0x010
/* This builtin is ultimately the way that all user-visible commands should
change the current working directory. It is called by cd_to_string (),
so the programming interface is simple, and it handles errors and
restrictions properly. */
int
cd_builtin (list)
WORD_LIST *list;
{
char *dirname, *cdpath, *path, *temp;
int path_index, no_symlinks, opt, lflag;
#if defined (RESTRICTED_SHELL)
if (restricted)
{
sh_restricted ((char *)NULL);
return (EXECUTION_FAILURE);
}
#endif /* RESTRICTED_SHELL */
no_symlinks = no_symbolic_links;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "LP")) != -1)
{
switch (opt)
{
case 'P':
no_symlinks = 1;
break;
case 'L':
no_symlinks = 0;
break;
default:
builtin_usage ();
return (EXECUTION_FAILURE);
}
}
list = loptend;
lflag = (cdable_vars ? LCD_DOVARS : 0) |
((interactive && cdspelling) ? LCD_DOSPELL : 0);
if (list == 0)
{
/* `cd' without arguments is equivalent to `cd $HOME' */
dirname = get_string_value ("HOME");
if (dirname == 0)
{
builtin_error (_("HOME not set"));
return (EXECUTION_FAILURE);
}
lflag = 0;
}
else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
{
/* This is `cd -', equivalent to `cd $OLDPWD' */
dirname = get_string_value ("OLDPWD");
if (dirname == 0)
{
builtin_error (_("OLDPWD not set"));
return (EXECUTION_FAILURE);
}
#if 0
lflag = interactive ? LCD_PRINTPATH : 0;
#else
lflag = LCD_PRINTPATH; /* According to SUSv3 */
#endif
}
else if (absolute_pathname (list->word->word))
dirname = list->word->word;
else if (cdpath = get_string_value ("CDPATH"))
{
dirname = list->word->word;
/* Find directory in $CDPATH. */
path_index = 0;
while (path = extract_colon_unit (cdpath, &path_index))
{
/* OPT is 1 if the path element is non-empty */
opt = path[0] != '\0';
temp = sh_makepath (path, dirname, MP_DOTILDE);
free (path);
if (change_to_directory (temp, no_symlinks))
{
/* POSIX.2 says that if a nonempty directory from CDPATH
is used to find the directory to change to, the new
directory name is echoed to stdout, whether or not
the shell is interactive. */
if (opt && (path = no_symlinks ? temp : the_current_working_directory))
printf ("%s\n", path);
free (temp);
#if 0
/* Posix.2 says that after using CDPATH, the resultant
value of $PWD will not contain `.' or `..'. */
return (bindpwd (posixly_correct || no_symlinks));
#else
return (bindpwd (no_symlinks));
#endif
}
else
free (temp);
}
/* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
try the current directory, so we just punt now with an error
message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
is so we don't mistakenly treat a CDPATH value of "" as not
specifying the current directory. */
if (posixly_correct && cdpath[0])
{
builtin_error ("%s: %s", dirname, strerror (ENOENT));
return (EXECUTION_FAILURE);
}
}
else
dirname = list->word->word;
/* When we get here, DIRNAME is the directory to change to. If we
chdir successfully, just return. */
if (change_to_directory (dirname, no_symlinks))
{
if (lflag & LCD_PRINTPATH)
printf ("%s\n", dirname);
return (bindpwd (no_symlinks));
}
/* If the user requests it, then perhaps this is the name of
a shell variable, whose value contains the directory to
change to. */
if (lflag & LCD_DOVARS)
{
temp = get_string_value (dirname);
if (temp && change_to_directory (temp, no_symlinks))
{
printf ("%s\n", temp);
return (bindpwd (no_symlinks));
}
}
/* If the user requests it, try to find a directory name similar in
spelling to the one requested, in case the user made a simple
typo. This is similar to the UNIX 8th and 9th Edition shells. */
if (lflag & LCD_DOSPELL)
{
temp = cdspell (dirname);
if (temp && change_to_directory (temp, no_symlinks))
{
printf ("%s\n", temp);
return (bindpwd (no_symlinks));
}
else
FREE (temp);
}
builtin_error ("%s: %s", dirname, strerror (errno));
return (EXECUTION_FAILURE);
}
$BUILTIN pwd
$FUNCTION pwd_builtin
$SHORT_DOC pwd [-LP]
Print the current working directory. With the -P option, pwd prints
the physical directory, without any symbolic links; the -L option
makes pwd follow symbolic links.
$END
/* Non-zero means that pwd always prints the physical directory, without
symbolic links. */
static int verbatim_pwd;
/* Print the name of the current working directory. */
int
pwd_builtin (list)
WORD_LIST *list;
{
char *directory;
int opt, pflag;
verbatim_pwd = no_symbolic_links;
pflag = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "LP")) != -1)
{
switch (opt)
{
case 'P':
verbatim_pwd = pflag = 1;
break;
case 'L':
verbatim_pwd = 0;
break;
default:
builtin_usage ();
return (EXECUTION_FAILURE);
}
}
list = loptend;
#define tcwd the_current_working_directory
directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
: get_working_directory ("pwd");
/* Try again using getcwd() if canonicalization fails (for instance, if
the file system has changed state underneath bash). */
if ((tcwd && directory == 0) ||
(posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
directory = resetpwd ("pwd");
#undef tcwd
if (directory)
{
printf ("%s\n", directory);
/* This is dumb but posix-mandated. */
if (posixly_correct && pflag)
setpwd (directory);
if (directory != the_current_working_directory)
free (directory);
fflush (stdout);
if (ferror (stdout))
{
sh_wrerror ();
clearerr (stdout);
return (EXECUTION_FAILURE);
}
return (EXECUTION_SUCCESS);
}
else
return (EXECUTION_FAILURE);
}
/* Do the work of changing to the directory NEWDIR. Handle symbolic
link following, etc. This function *must* return with
the_current_working_directory either set to NULL (in which case
getcwd() will eventually be called), or set to a string corresponding
to the working directory. Return 1 on success, 0 on failure. */
static int
change_to_directory (newdir, nolinks)
char *newdir;
int nolinks;
{
char *t, *tdir;
int err, canon_failed, r, ndlen, dlen;
tdir = (char *)NULL;
if (the_current_working_directory == 0)
{
t = get_working_directory ("chdir");
FREE (t);
}
t = make_absolute (newdir, the_current_working_directory);
/* TDIR is either the canonicalized absolute pathname of NEWDIR
(nolinks == 0) or the absolute physical pathname of NEWDIR
(nolinks != 0). */
tdir = nolinks ? sh_physpath (t, 0)
: sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
ndlen = strlen (newdir);
dlen = strlen (t);
/* Use the canonicalized version of NEWDIR, or, if canonicalization
failed, use the non-canonical form. */
canon_failed = 0;
if (tdir && *tdir)
free (t);
else
{
FREE (tdir);
tdir = t;
canon_failed = 1;
}
/* In POSIX mode, if we're resolving symlinks logically and sh_canonpath
returns NULL (because it checks the path, it will return NULL if the
resolved path doesn't exist), fail immediately. */
if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
{
#if defined ENAMETOOLONG
if (errno != ENOENT && errno != ENAMETOOLONG)
#else
if (errno != ENOENT)
#endif
errno = ENOTDIR;
free (tdir);
return (0);
}
/* If the chdir succeeds, update the_current_working_directory. */
if (chdir (nolinks ? newdir : tdir) == 0)
{
/* If canonicalization failed, but the chdir succeeded, reset the
shell's idea of the_current_working_directory. */
if (canon_failed)
{
t = resetpwd ("cd");
if (t == 0)
set_working_directory (tdir);
}
else
set_working_directory (tdir);
free (tdir);
return (1);
}
/* We failed to change to the appropriate directory name. If we tried
what the user passed (nolinks != 0), punt now. */
if (nolinks)
{
free (tdir);
return (0);
}
err = errno;
/* We're not in physical mode (nolinks == 0), but we failed to change to
the canonicalized directory name (TDIR). Try what the user passed
verbatim. If we succeed, reinitialize the_current_working_directory. */
if (chdir (newdir) == 0)
{
t = resetpwd ("cd");
if (t == 0)
set_working_directory (tdir);
else
free (t);
r = 1;
}
else
{
errno = err;
r = 0;
}
free (tdir);
return r;
}
/* Code for cd spelling correction. Original patch submitted by
Neil Russel (caret@c-side.com). */
static char *
cdspell (dirname)
char *dirname;
{
int n;
char *guess;
n = (strlen (dirname) * 3 + 1) / 2 + 1;
guess = (char *)xmalloc (n);
switch (spname (dirname, guess))
{
case -1:
default:
free (guess);
return (char *)NULL;
case 0:
case 1:
return guess;
}
}
-3
View File
@@ -467,9 +467,6 @@ char *
get_working_directory (for_whom)
char *for_whom;
{
char *directory;
size_t dsize;
if (no_symbolic_links)
{
FREE (the_current_working_directory);
+2
View File
@@ -31,6 +31,8 @@ $PRODUCES echo.c
#include <stdio.h>
#include "../shell.h"
#include "common.h"
$BUILTIN echo
$FUNCTION echo_builtin
$DEPENDS_ON V9_ECHO
+183
View File
@@ -0,0 +1,183 @@
This file is echo.def, from which is created echo.c.
It implements the builtin "echo" in Bash.
Copyright (C) 1987-2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
$PRODUCES echo.c
#include <config.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashansi.h"
#include <stdio.h>
#include "../shell.h"
$BUILTIN echo
$FUNCTION echo_builtin
$DEPENDS_ON V9_ECHO
$SHORT_DOC echo [-neE] [arg ...]
Output the ARGs. If -n is specified, the trailing newline is
suppressed. If the -e option is given, interpretation of the
following backslash-escaped characters is turned on:
\a alert (bell)
\b backspace
\c suppress trailing newline
\E escape character
\f form feed
\n new line
\r carriage return
\t horizontal tab
\v vertical tab
\\ backslash
\num the character whose ASCII code is NUM (octal).
You can explicitly turn off the interpretation of the above characters
with the -E option.
$END
$BUILTIN echo
$FUNCTION echo_builtin
$DEPENDS_ON !V9_ECHO
$SHORT_DOC echo [-n] [arg ...]
Output the ARGs. If -n is specified, the trailing newline is suppressed.
$END
#if defined (V9_ECHO)
# define VALID_ECHO_OPTIONS "neE"
#else /* !V9_ECHO */
# define VALID_ECHO_OPTIONS "n"
#endif /* !V9_ECHO */
/* System V machines already have a /bin/sh with a v9 behaviour. We
give Bash the identical behaviour for these machines so that the
existing system shells won't barf. Regrettably, the SUS v2 has
standardized the Sys V echo behavior. This variable is external
so that we can have a `shopt' variable to control it at runtime. */
#if defined (DEFAULT_ECHO_TO_XPG) || defined (STRICT_POSIX)
int xpg_echo = 1;
#else
int xpg_echo = 0;
#endif /* DEFAULT_ECHO_TO_XPG */
extern int posixly_correct;
/* Print the words in LIST to standard output. If the first word is
`-n', then don't print a trailing newline. We also support the
echo syntax from Version 9 Unix systems. */
int
echo_builtin (list)
WORD_LIST *list;
{
int display_return, do_v9, i, len;
char *temp, *s;
do_v9 = xpg_echo;
display_return = 1;
if (posixly_correct && xpg_echo)
goto just_echo;
for (; list && (temp = list->word->word) && *temp == '-'; list = list->next)
{
/* If it appears that we are handling options, then make sure that
all of the options specified are actually valid. Otherwise, the
string should just be echoed. */
temp++;
for (i = 0; temp[i]; i++)
{
if (strchr (VALID_ECHO_OPTIONS, temp[i]) == 0)
break;
}
/* echo - and echo -<nonopt> both mean to just echo the arguments. */
if (*temp == 0 || temp[i])
break;
/* All of the options in TEMP are valid options to ECHO.
Handle them. */
while (i = *temp++)
{
switch (i)
{
case 'n':
display_return = 0;
break;
#if defined (V9_ECHO)
case 'e':
do_v9 = 1;
break;
case 'E':
do_v9 = 0;
break;
#endif /* V9_ECHO */
default:
goto just_echo; /* XXX */
}
}
}
just_echo:
clearerr (stdout); /* clear error before writing and testing success */
while (list)
{
i = len = 0;
temp = do_v9 ? ansicstr (list->word->word, STRLEN (list->word->word), 1, &i, &len)
: list->word->word;
if (temp)
{
if (do_v9)
{
for (s = temp; len > 0; len--)
putchar (*s++);
}
else
printf ("%s", temp);
#if defined (SunOS5)
fflush (stdout); /* Fix for bug in SunOS 5.5 printf(3) */
#endif
}
if (do_v9 && temp)
free (temp);
list = list->next;
if (i)
{
display_return = 0;
break;
}
if (list)
putchar(' ');
}
if (display_return)
putchar ('\n');
fflush (stdout);
if (ferror (stdout))
{
sh_wrerror ();
clearerr (stdout);
return (EXECUTION_FAILURE);
}
return (EXECUTION_SUCCESS);
}
+1 -1
View File
@@ -63,7 +63,7 @@ extern int errno;
#define FEVAL_NOPUSHARGS 0x100
extern int posixly_correct;
extern int indirection_level, startup_state, subshell_environment;
extern int indirection_level, subshell_environment;
extern int return_catch_flag, return_catch_value;
extern int last_command_exit_value;
-1
View File
@@ -201,7 +201,6 @@ file_error_and_exit:
#if defined (ARRAY_VARS)
array_push (bash_source_a, (char *)filename);
t = itos (executing_line_number ());
itrace("evalfile: pushing %s to bash_lineno array");
array_push (bash_lineno_a, t);
free (t);
array_push (funcname_a, "source"); /* not exactly right */
+2 -3
View File
@@ -56,7 +56,7 @@ extern int errno;
#define IS_BUILTIN(s) (builtin_address_internal(s, 0) != (struct builtin *)NULL)
extern int indirection_level, startup_state, subshell_environment;
extern int indirection_level, subshell_environment;
extern int line_number;
extern int last_command_exit_value;
extern int running_trap;
@@ -316,9 +316,8 @@ static int
cat_file (r)
REDIRECT *r;
{
char lbuf[128], *fn;
char *fn;
int fd, rval;
ssize_t nr;
if (r->instruction != r_input_direction)
return -1;
+352
View File
@@ -0,0 +1,352 @@
/* Evaluate a string as one or more shell commands.
Copyright (C) 1996-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include "filecntl.h"
#include "../bashansi.h"
#include "../shell.h"
#include "../jobs.h"
#include "../builtins.h"
#include "../flags.h"
#include "../input.h"
#include "../execute_cmd.h"
#include "../redir.h"
#include "../trap.h"
#if defined (HISTORY)
# include "../bashhist.h"
#endif
#include "common.h"
#if !defined (errno)
extern int errno;
#endif
#define IS_BUILTIN(s) (builtin_address_internal(s, 0) != (struct builtin *)NULL)
extern int indirection_level, startup_state, subshell_environment;
extern int line_number;
extern int last_command_exit_value;
extern int running_trap;
extern int loop_level;
extern int posixly_correct;
int parse_and_execute_level = 0;
static int cat_file __P((REDIRECT *));
/* How to force parse_and_execute () to clean up after itself. */
void
parse_and_execute_cleanup ()
{
if (running_trap)
{
run_trap_cleanup (running_trap - 1);
unfreeze_jobs_list ();
}
run_unwind_frame ("parse_and_execute_top");
}
/* Parse and execute the commands in STRING. Returns whatever
execute_command () returns. This frees STRING. FLAGS is a
flags word; look in common.h for the possible values. Actions
are:
(flags & SEVAL_NONINT) -> interactive = 0;
(flags & SEVAL_INTERACT) -> interactive = 1;
(flags & SEVAL_NOHIST) -> call bash_history_disable ()
(flags & SEVAL_NOFREE) -> don't free STRING when finished
(flags & SEVAL_RESETLINE) -> reset line_number to 1
*/
int
parse_and_execute (string, from_file, flags)
char *string;
const char *from_file;
int flags;
{
int code, x, lreset;
volatile int should_jump_to_top_level, last_result;
char *orig_string;
COMMAND *volatile command;
orig_string = string;
/* Unwind protect this invocation of parse_and_execute (). */
begin_unwind_frame ("parse_and_execute_top");
unwind_protect_int (parse_and_execute_level);
unwind_protect_jmp_buf (top_level);
unwind_protect_int (indirection_level);
unwind_protect_int (line_number);
unwind_protect_int (loop_level);
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
unwind_protect_int (interactive);
lreset = flags & SEVAL_RESETLINE;
#if defined (HISTORY)
unwind_protect_int (remember_on_history); /* can be used in scripts */
# if defined (BANG_HISTORY)
if (interactive_shell)
{
unwind_protect_int (history_expansion_inhibited);
}
# endif /* BANG_HISTORY */
#endif /* HISTORY */
if (interactive_shell)
{
x = get_current_prompt_level ();
add_unwind_protect (set_current_prompt_level, x);
}
add_unwind_protect (pop_stream, (char *)NULL);
if (orig_string && ((flags & SEVAL_NOFREE) == 0))
add_unwind_protect (xfree, orig_string);
end_unwind_frame ();
parse_and_execute_level++;
/* Reset the line number if the caller wants us to. If we don't reset the
line number, we have to subtract one, because we will add one just
before executing the next command (resetting the line number sets it to
0; the first line number is 1). */
push_stream (lreset);
if (lreset == 0)
line_number--;
indirection_level++;
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
interactive = (flags & SEVAL_NONINT) ? 0 : 1;
#if defined (HISTORY)
if (flags & SEVAL_NOHIST)
bash_history_disable ();
#endif /* HISTORY */
code = should_jump_to_top_level = 0;
last_result = EXECUTION_SUCCESS;
with_input_from_string (string, from_file);
while (*(bash_input.location.string))
{
command = (COMMAND *)NULL;
if (interrupt_state)
{
last_result = EXECUTION_FAILURE;
break;
}
/* Provide a location for functions which `longjmp (top_level)' to
jump to. This prevents errors in substitution from restarting
the reader loop directly, for example. */
code = setjmp (top_level);
if (code)
{
should_jump_to_top_level = 0;
switch (code)
{
case FORCE_EOF:
case ERREXIT:
case EXITPROG:
if (command)
run_unwind_frame ("pe_dispose");
/* Remember to call longjmp (top_level) after the old
value for it is restored. */
should_jump_to_top_level = 1;
goto out;
case DISCARD:
if (command)
run_unwind_frame ("pe_dispose");
last_result = last_command_exit_value = EXECUTION_FAILURE; /* XXX */
if (subshell_environment)
{
should_jump_to_top_level = 1;
goto out;
}
else
{
#if 0
dispose_command (command); /* pe_dispose does this */
#endif
continue;
}
default:
command_error ("parse_and_execute", CMDERR_BADJUMP, code, 0);
break;
}
}
if (parse_command () == 0)
{
if (interactive_shell == 0 && read_but_dont_execute)
{
last_result = EXECUTION_SUCCESS;
dispose_command (global_command);
global_command = (COMMAND *)NULL;
}
else if (command = global_command)
{
struct fd_bitmap *bitmap;
bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
begin_unwind_frame ("pe_dispose");
add_unwind_protect (dispose_fd_bitmap, bitmap);
add_unwind_protect (dispose_command, command); /* XXX */
global_command = (COMMAND *)NULL;
#if defined (ONESHOT)
/*
* IF
* we were invoked as `bash -c' (startup_state == 2) AND
* parse_and_execute has not been called recursively AND
* we're not running a trap AND
* we have parsed the full command (string == '\0') AND
* we have a simple command without redirections AND
* the command is not being timed AND
* the command's return status is not being inverted
* THEN
* tell the execution code that we don't need to fork
*/
if (startup_state == 2 && parse_and_execute_level == 1 &&
running_trap == 0 &&
*bash_input.location.string == '\0' &&
command->type == cm_simple &&
!command->redirects && !command->value.Simple->redirects &&
((command->flags & CMD_TIME_PIPELINE) == 0) &&
((command->flags & CMD_INVERT_RETURN) == 0))
{
command->flags |= CMD_NO_FORK;
command->value.Simple->flags |= CMD_NO_FORK;
}
#endif /* ONESHOT */
/* See if this is a candidate for $( <file ). */
if (startup_state == 2 &&
(subshell_environment & SUBSHELL_COMSUB) &&
*bash_input.location.string == '\0' &&
command->type == cm_simple && !command->redirects &&
(command->flags & CMD_TIME_PIPELINE) == 0 &&
command->value.Simple->words == 0 &&
command->value.Simple->redirects &&
command->value.Simple->redirects->next == 0 &&
command->value.Simple->redirects->instruction == r_input_direction)
{
int r;
r = cat_file (command->value.Simple->redirects);
last_result = (r < 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
}
else
last_result = execute_command_internal
(command, 0, NO_PIPE, NO_PIPE, bitmap);
dispose_command (command);
dispose_fd_bitmap (bitmap);
discard_unwind_frame ("pe_dispose");
}
}
else
{
last_result = EXECUTION_FAILURE;
/* Since we are shell compatible, syntax errors in a script
abort the execution of the script. Right? */
break;
}
}
out:
run_unwind_frame ("parse_and_execute_top");
if (interrupt_state && parse_and_execute_level == 0)
{
/* An interrupt during non-interactive execution in an
interactive shell (e.g. via $PROMPT_COMMAND) should
not cause the shell to exit. */
interactive = interactive_shell;
throw_to_top_level ();
}
if (should_jump_to_top_level)
jump_to_top_level (code);
return (last_result);
}
/* Handle a $( < file ) command substitution. This expands the filename,
returning errors as appropriate, then just cats the file to the standard
output. */
static int
cat_file (r)
REDIRECT *r;
{
char *fn;
int fd, rval;
if (r->instruction != r_input_direction)
return -1;
/* Get the filename. */
if (posixly_correct && !interactive_shell)
disallow_filename_globbing++;
fn = redirection_expand (r->redirectee.filename);
if (posixly_correct && !interactive_shell)
disallow_filename_globbing--;
if (fn == 0)
{
redirection_error (r, AMBIGUOUS_REDIRECT);
return -1;
}
fd = open(fn, O_RDONLY);
if (fd < 0)
{
file_error (fn);
free (fn);
return -1;
}
rval = zcatfd (fd, 1, fn);
free (fn);
close (fd);
return (rval);
}
-1
View File
@@ -81,7 +81,6 @@ $END
extern int errno;
#endif /* !errno */
extern int echo_input_at_read;
extern int current_command_line_count;
extern int literal_history;
extern int posixly_correct;
+631
View File
@@ -0,0 +1,631 @@
This file is fc.def, from which is created fc.c.
It implements the builtin "fc" in Bash.
Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
$PRODUCES fc.c
$BUILTIN fc
$FUNCTION fc_builtin
$DEPENDS_ON HISTORY
$SHORT_DOC fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [cmd]
fc is used to list or edit and re-execute commands from the history list.
FIRST and LAST can be numbers specifying the range, or FIRST can be a
string, which means the most recent command beginning with that
string.
-e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
then vi.
-l means list lines instead of editing.
-n means no line numbers listed.
-r means reverse the order of the lines (making it newest listed first).
With the `fc -s [pat=rep ...] [command]' format, the command is
re-executed after the substitution OLD=NEW is performed.
A useful alias to use with this is r='fc -s', so that typing `r cc'
runs the last command beginning with `cc' and typing `r' re-executes
the last command.
$END
#include <config.h>
#if defined (HISTORY)
#ifndef _MINIX
# include <sys/param.h>
#endif
#include "../bashtypes.h"
#include "posixstat.h"
#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include <chartypes.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include <errno.h>
#include "../shell.h"
#include "../builtins.h"
#include "../flags.h"
#include "../bashhist.h"
#include "maxpath.h"
#include <readline/history.h>
#include "bashgetopt.h"
#include "common.h"
#if !defined (errno)
extern int errno;
#endif /* !errno */
extern int echo_input_at_read;
extern int current_command_line_count;
extern int literal_history;
extern int posixly_correct;
extern int unlink __P((const char *));
extern FILE *sh_mktmpfp __P((char *, int, char **));
extern int delete_last_history __P((void));
/* **************************************************************** */
/* */
/* The K*rn shell style fc command (Fix Command) */
/* */
/* **************************************************************** */
/* fc builtin command (fix command) for Bash for those who
like K*rn-style history better than csh-style.
fc [-e ename] [-nlr] [first] [last]
FIRST and LAST can be numbers specifying the range, or FIRST can be
a string, which means the most recent command beginning with that
string.
-e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
then the editor which corresponds to the current readline editing
mode, then vi.
-l means list lines instead of editing.
-n means no line numbers listed.
-r means reverse the order of the lines (making it newest listed first).
fc -e - [pat=rep ...] [command]
fc -s [pat=rep ...] [command]
Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
*/
/* Data structure describing a list of global replacements to perform. */
typedef struct repl {
struct repl *next;
char *pat;
char *rep;
} REPL;
/* Accessors for HIST_ENTRY lists that are called HLIST. */
#define histline(i) (hlist[(i)]->line)
#define histdata(i) (hlist[(i)]->data)
#define FREE_RLIST() \
do { \
for (rl = rlist; rl; ) { \
REPL *r; \
r = rl->next; \
if (rl->pat) \
free (rl->pat); \
if (rl->rep) \
free (rl->rep); \
free (rl); \
rl = r; \
} \
} while (0)
static char *fc_dosubs __P((char *, REPL *));
static char *fc_gethist __P((char *, HIST_ENTRY **));
static int fc_gethnum __P((char *, HIST_ENTRY **));
static int fc_number __P((WORD_LIST *));
static void fc_replhist __P((char *));
#ifdef INCLUDE_UNUSED
static char *fc_readline __P((FILE *));
static void fc_addhist __P((char *));
#endif
/* String to execute on a file that we want to edit. */
#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
#if defined (STRICT_POSIX)
# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-ed}"
#else
# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}"
#endif
int
fc_builtin (list)
WORD_LIST *list;
{
register int i;
register char *sep;
int numbering, reverse, listing, execute;
int histbeg, histend, last_hist, retval, opt;
FILE *stream;
REPL *rlist, *rl;
char *ename, *command, *newcom, *fcedit;
HIST_ENTRY **hlist;
char *fn;
numbering = 1;
reverse = listing = execute = 0;
ename = (char *)NULL;
/* Parse out the options and set which of the two forms we're in. */
reset_internal_getopt ();
lcurrent = list; /* XXX */
while (fc_number (loptend = lcurrent) == 0 &&
(opt = internal_getopt (list, ":e:lnrs")) != -1)
{
switch (opt)
{
case 'n':
numbering = 0;
break;
case 'l':
listing = 1;
break;
case 'r':
reverse = 1;
break;
case 's':
execute = 1;
break;
case 'e':
ename = list_optarg;
break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (ename && (*ename == '-') && (ename[1] == '\0'))
execute = 1;
/* The "execute" form of the command (re-run, with possible string
substitutions). */
if (execute)
{
rlist = (REPL *)NULL;
while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
{
*sep++ = '\0';
rl = (REPL *)xmalloc (sizeof (REPL));
rl->next = (REPL *)NULL;
rl->pat = savestring (list->word->word);
rl->rep = savestring (sep);
if (rlist == NULL)
rlist = rl;
else
{
rl->next = rlist;
rlist = rl;
}
list = list->next;
}
/* If we have a list of substitutions to do, then reverse it
to get the replacements in the proper order. */
rlist = REVERSE_LIST (rlist, REPL *);
hlist = history_list ();
/* If we still have something in list, it is a command spec.
Otherwise, we use the most recent command in time. */
command = fc_gethist (list ? list->word->word : (char *)NULL, hlist);
if (command == NULL)
{
builtin_error (_("no command found"));
if (rlist)
FREE_RLIST ();
return (EXECUTION_FAILURE);
}
if (rlist)
{
newcom = fc_dosubs (command, rlist);
free (command);
FREE_RLIST ();
command = newcom;
}
fprintf (stderr, "%s\n", command);
fc_replhist (command); /* replace `fc -s' with command */
return (parse_and_execute (command, "fc", SEVAL_NOHIST));
}
/* This is the second form of the command (the list-or-edit-and-rerun
form). */
hlist = history_list ();
if (hlist == 0)
return (EXECUTION_SUCCESS);
for (i = 0; hlist[i]; i++);
/* With the Bash implementation of history, the current command line
("fc blah..." and so on) is already part of the history list by
the time we get to this point. This just skips over that command
and makes the last command that this deals with be the last command
the user entered before the fc. We need to check whether the
line was actually added (HISTIGNORE may have caused it to not be),
so we check hist_last_line_added. */
/* "When not listing, he fc command that caused the editing shall not be
entered into the history list." */
if (listing == 0 && hist_last_line_added)
delete_last_history ();
last_hist = i - 1 - hist_last_line_added;
if (list)
{
histbeg = fc_gethnum (list->word->word, hlist);
list = list->next;
if (list)
histend = fc_gethnum (list->word->word, hlist);
else
histend = listing ? last_hist : histbeg;
}
else
{
/* The default for listing is the last 16 history items. */
if (listing)
{
histend = last_hist;
histbeg = histend - 16 + 1; /* +1 because loop below uses >= */
if (histbeg < 0)
histbeg = 0;
}
else
/* For editing, it is the last history command. */
histbeg = histend = last_hist;
}
/* We print error messages for line specifications out of range. */
if ((histbeg < 0) || (histend < 0))
{
sh_erange ((char *)NULL, _("history specification"));
return (EXECUTION_FAILURE);
}
if (histend < histbeg)
{
i = histend;
histend = histbeg;
histbeg = i;
reverse = 1;
}
if (listing)
stream = stdout;
else
{
numbering = 0;
stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
if (stream == 0)
{
builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno));
FREE (fn);
return (EXECUTION_FAILURE);
}
}
for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
{
QUIT;
if (numbering)
fprintf (stream, "%d", i + history_base);
if (listing)
{
if (posixly_correct)
fputs ("\t", stream);
else
fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
}
fprintf (stream, "%s\n", histline (i));
}
if (listing)
return (EXECUTION_SUCCESS);
fclose (stream);
/* Now edit the file of commands. */
if (ename)
{
command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
sprintf (command, "%s %s", ename, fn);
}
else
{
fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND;
command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn));
sprintf (command, "%s %s", fcedit, fn);
}
retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
if (retval != EXECUTION_SUCCESS)
{
unlink (fn);
free (fn);
return (EXECUTION_FAILURE);
}
/* Make sure parse_and_execute doesn't turn this off, even though a
call to parse_and_execute farther up the function call stack (e.g.,
if this is called by vi_edit_and_execute_command) may have already
called bash_history_disable. */
remember_on_history = 1;
/* Turn on the `v' flag while fc_execute_file runs so the commands
will be echoed as they are read by the parser. */
begin_unwind_frame ("fc builtin");
add_unwind_protect ((Function *)xfree, fn);
add_unwind_protect (unlink, fn);
unwind_protect_int (echo_input_at_read);
echo_input_at_read = 1;
retval = fc_execute_file (fn);
run_unwind_frame ("fc builtin");
return (retval);
}
/* Return 1 if LIST->word->word is a legal number for fc's use. */
static int
fc_number (list)
WORD_LIST *list;
{
char *s;
if (list == 0)
return 0;
s = list->word->word;
if (*s == '-')
s++;
return (legal_number (s, (intmax_t *)NULL));
}
/* Return an absolute index into HLIST which corresponds to COMMAND. If
COMMAND is a number, then it was specified in relative terms. If it
is a string, then it is the start of a command line present in HLIST. */
static int
fc_gethnum (command, hlist)
char *command;
HIST_ENTRY **hlist;
{
int sign = 1, n, clen;
register int i, j;
register char *s;
/* Count history elements. */
for (i = 0; hlist[i]; i++);
/* With the Bash implementation of history, the current command line
("fc blah..." and so on) is already part of the history list by
the time we get to this point. This just skips over that command
and makes the last command that this deals with be the last command
the user entered before the fc. We need to check whether the
line was actually added (HISTIGNORE may have caused it to not be),
so we check hist_last_line_added. */
i -= 1 + hist_last_line_added;
/* No specification defaults to most recent command. */
if (command == NULL)
return (i);
/* Otherwise, there is a specification. It can be a number relative to
the current position, or an absolute history number. */
s = command;
/* Handle possible leading minus sign. */
if (s && (*s == '-'))
{
sign = -1;
s++;
}
if (s && DIGIT(*s))
{
n = atoi (s);
n *= sign;
/* If the value is negative or zero, then it is an offset from
the current history item. */
if (n < 0)
{
n += i + 1;
return (n < 0 ? 0 : n);
}
else if (n == 0)
return (i);
else
{
n -= history_base;
return (i < n ? i : n);
}
}
clen = strlen (command);
for (j = i; j >= 0; j--)
{
if (STREQN (command, histline (j), clen))
return (j);
}
return (-1);
}
/* Locate the most recent history line which begins with
COMMAND in HLIST, and return a malloc()'ed copy of it. */
static char *
fc_gethist (command, hlist)
char *command;
HIST_ENTRY **hlist;
{
int i;
if (hlist == 0)
return ((char *)NULL);
i = fc_gethnum (command, hlist);
if (i >= 0)
return (savestring (histline (i)));
else
return ((char *)NULL);
}
#ifdef INCLUDE_UNUSED
/* Read the edited history lines from STREAM and return them
one at a time. This can read unlimited length lines. The
caller should free the storage. */
static char *
fc_readline (stream)
FILE *stream;
{
register int c;
int line_len = 0, lindex = 0;
char *line = (char *)NULL;
while ((c = getc (stream)) != EOF)
{
if ((lindex + 2) >= line_len)
line = (char *)xrealloc (line, (line_len += 128));
if (c == '\n')
{
line[lindex++] = '\n';
line[lindex++] = '\0';
return (line);
}
else
line[lindex++] = c;
}
if (!lindex)
{
if (line)
free (line);
return ((char *)NULL);
}
if (lindex + 2 >= line_len)
line = (char *)xrealloc (line, lindex + 3);
line[lindex++] = '\n'; /* Finish with newline if none in file */
line[lindex++] = '\0';
return (line);
}
#endif
/* Perform the SUBS on COMMAND.
SUBS is a list of substitutions, and COMMAND is a simple string.
Return a pointer to a malloc'ed string which contains the substituted
command. */
static char *
fc_dosubs (command, subs)
char *command;
REPL *subs;
{
register char *new, *t;
register REPL *r;
for (new = savestring (command), r = subs; r; r = r->next)
{
t = strsub (new, r->pat, r->rep, 1);
free (new);
new = t;
}
return (new);
}
/* Use `command' to replace the last entry in the history list, which,
by this time, is `fc blah...'. The intent is that the new command
become the history entry, and that `fc' should never appear in the
history list. This way you can do `r' to your heart's content. */
static void
fc_replhist (command)
char *command;
{
int n;
if (command == 0 || *command == '\0')
return;
n = strlen (command);
if (command[n - 1] == '\n')
command[n - 1] = '\0';
if (command && *command)
{
delete_last_history ();
maybe_add_history (command); /* Obeys HISTCONTROL setting. */
}
}
#ifdef INCLUDE_UNUSED
/* Add LINE to the history, after removing a single trailing newline. */
static void
fc_addhist (line)
char *line;
{
register int n;
if (line == 0 || *line == 0)
return;
n = strlen (line);
if (line[n - 1] == '\n')
line[n - 1] = '\0';
if (line && *line)
maybe_add_history (line); /* Obeys HISTCONTROL setting. */
}
#endif
#endif /* HISTORY */
+2 -1
View File
@@ -108,6 +108,7 @@ extern int errno;
(void)fputs (b, stdout); \
if (ferror (stdout)) \
{ \
sh_wrerror (); \
clearerr (stdout); \
return (EXECUTION_FAILURE); \
} \
@@ -826,7 +827,7 @@ vbadd (buf, blen)
#ifdef DEBUG
if (strlen (vbuf) != vblen)
internal_error ("printf:vbadd: vblen (%d) != strlen (vbuf) (%d)", vblen, strlen (vbuf));
internal_error ("printf:vbadd: vblen (%d) != strlen (vbuf) (%d)", vblen, (int)strlen (vbuf));
#endif
return vbuf;
+1008
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -578,7 +578,6 @@ set_builtin (list)
WORD_LIST *list;
{
int on_or_off, flag_name, force_assignment, opts_changed;
WORD_LIST *l;
register char *arg;
char s[3];
+1 -3
View File
@@ -68,9 +68,7 @@ $END
extern int errno;
#endif /* !errno */
#if defined (RESTRICTED_SHELL)
extern int restricted;
#endif
static void maybe_pop_dollar_vars __P((void));
/* If non-zero, `.' uses $PATH to look up the script to be sourced. */
int source_uses_path = 1;
+174
View File
@@ -0,0 +1,174 @@
This file is source.def, from which is created source.c.
It implements the builtins "." and "source" in Bash.
Copyright (C) 1987-2003 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
$PRODUCES source.c
$BUILTIN source
$FUNCTION source_builtin
$SHORT_DOC source filename [arguments]
Read and execute commands from FILENAME and return. The pathnames
in $PATH are used to find the directory containing FILENAME. If any
ARGUMENTS are supplied, they become the positional parameters when
FILENAME is executed.
$END
$BUILTIN .
$DOCNAME dot
$FUNCTION source_builtin
$SHORT_DOC . filename [arguments]
Read and execute commands from FILENAME and return. The pathnames
in $PATH are used to find the directory containing FILENAME. If any
ARGUMENTS are supplied, they become the positional parameters when
FILENAME is executed.
$END
/* source.c - Implements the `.' and `source' builtins. */
#include <config.h>
#include "../bashtypes.h"
#include "posixstat.h"
#include "filecntl.h"
#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#include <errno.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../flags.h"
#include "../findcmd.h"
#include "common.h"
#include "bashgetopt.h"
#include "../trap.h"
#if !defined (errno)
extern int errno;
#endif /* !errno */
#if defined (RESTRICTED_SHELL)
extern int restricted;
#endif
/* If non-zero, `.' uses $PATH to look up the script to be sourced. */
int source_uses_path = 1;
/* If non-zero, `.' looks in the current directory if the filename argument
is not found in the $PATH. */
int source_searches_cwd = 1;
/* If this . script is supplied arguments, we save the dollar vars and
replace them with the script arguments for the duration of the script's
execution. If the script does not change the dollar vars, we restore
what we saved. If the dollar vars are changed in the script, and we are
not executing a shell function, we leave the new values alone and free
the saved values. */
static void
maybe_pop_dollar_vars ()
{
if (variable_context == 0 && (dollar_vars_changed () & ARGS_SETBLTIN))
dispose_saved_dollar_vars ();
else
pop_dollar_vars ();
if (debugging_mode)
pop_args (); /* restore BASH_ARGC and BASH_ARGV */
set_dollar_vars_unchanged ();
}
/* Read and execute commands from the file passed as argument. Guess what.
This cannot be done in a subshell, since things like variable assignments
take place in there. So, I open the file, place it into a large string,
close the file, and then execute the string. */
int
source_builtin (list)
WORD_LIST *list;
{
int result;
char *filename, *debug_trap;
if (no_options (list))
return (EX_USAGE);
list = loptend;
if (list == 0)
{
builtin_error (_("filename argument required"));
builtin_usage ();
return (EX_USAGE);
}
#if defined (RESTRICTED_SHELL)
if (restricted && strchr (list->word->word, '/'))
{
sh_restricted (list->word->word);
return (EXECUTION_FAILURE);
}
#endif
filename = (char *)NULL;
if (source_uses_path)
filename = find_path_file (list->word->word);
if (filename == 0)
{
if (source_searches_cwd == 0)
{
builtin_error (_("%s: file not found"), list->word->word);
return (EXECUTION_FAILURE);
}
else
filename = savestring (list->word->word);
}
begin_unwind_frame ("source");
add_unwind_protect ((Function *)xfree, filename);
if (list->next)
{
push_dollar_vars ();
add_unwind_protect ((Function *)maybe_pop_dollar_vars, (char *)NULL);
remember_args (list->next, 1);
if (debugging_mode)
push_args (list->next); /* Update BASH_ARGV and BASH_ARGC */
}
set_dollar_vars_unchanged ();
/* Don't inherit the DEBUG trap unless function_trace_mode (overloaded)
is set. XXX - should sourced files inherit the RETURN trap? Functions
don't. */
debug_trap = TRAP_STRING (DEBUG_TRAP);
if (debug_trap && function_trace_mode == 0)
{
debug_trap = savestring (debug_trap);
add_unwind_protect (xfree, debug_trap);
add_unwind_protect (set_debug_trap, debug_trap);
restore_default_signal (DEBUG_TRAP);
}
result = source_file (filename, (list && list->next));
run_unwind_frame ("source");
return (result);
}
+3 -1
View File
@@ -48,13 +48,15 @@ $END
#include "common.h"
#include "bashgetopt.h"
static sighandler suspend_continue __P((int));
static SigHandler *old_cont;
#if 0
static SigHandler *old_stop;
#endif
/* Continue handler. */
sighandler
static sighandler
suspend_continue (sig)
int sig;
{
+119
View File
@@ -0,0 +1,119 @@
This file is suspend.def, from which is created suspend.c.
It implements the builtin "suspend" in Bash.
Copyright (C) 1987-2003 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
$PRODUCES suspend.c
$BUILTIN suspend
$DEPENDS_ON JOB_CONTROL
$FUNCTION suspend_builtin
$SHORT_DOC suspend [-f]
Suspend the execution of this shell until it receives a SIGCONT
signal. The `-f' if specified says not to complain about this
being a login shell if it is; just suspend anyway.
$END
#include <config.h>
#if defined (JOB_CONTROL)
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashtypes.h"
#include <signal.h>
#include "../bashintl.h"
#include "../shell.h"
#include "../jobs.h"
#include "common.h"
#include "bashgetopt.h"
static SigHandler *old_cont;
#if 0
static SigHandler *old_stop;
#endif
/* Continue handler. */
sighandler
suspend_continue (sig)
int sig;
{
set_signal_handler (SIGCONT, old_cont);
#if 0
set_signal_handler (SIGSTOP, old_stop);
#endif
SIGRETURN (0);
}
/* Suspending the shell. If -f is the arg, then do the suspend
no matter what. Otherwise, complain if a login shell. */
int
suspend_builtin (list)
WORD_LIST *list;
{
int opt, force;
reset_internal_getopt ();
force = 0;
while ((opt = internal_getopt (list, "f")) != -1)
switch (opt)
{
case 'f':
force++;
break;
default:
builtin_usage ();
return (EX_USAGE);
}
list = loptend;
if (job_control == 0)
{
sh_nojobs (_("cannot suspend"));
return (EXECUTION_FAILURE);
}
if (force == 0)
{
no_args (list);
if (login_shell)
{
builtin_error (_("cannot suspend a login shell"));
return (EXECUTION_FAILURE);
}
}
/* XXX - should we put ourselves back into the original pgrp now? If so,
call end_job_control() here and do the right thing in suspend_continue
(that is, call restart_job_control()). */
old_cont = (SigHandler *)set_signal_handler (SIGCONT, suspend_continue);
#if 0
old_stop = (SigHandler *)set_signal_handler (SIGSTOP, SIG_DFL);
#endif
killpg (shell_pgrp, SIGSTOP);
return (EXECUTION_SUCCESS);
}
#endif /* JOB_CONTROL */
+1 -1
View File
@@ -87,7 +87,7 @@ int
trap_builtin (list)
WORD_LIST *list;
{
int list_signal_names, display, result, opt, first_signal;
int list_signal_names, display, result, opt;
list_signal_names = display = 0;
result = EXECUTION_SUCCESS;
-1
View File
@@ -59,7 +59,6 @@ $END
#include "common.h"
#include "bashgetopt.h"
extern int interrupt_immediately;
extern int wait_signal_received;
procenv_t wait_intr_buf;
+177
View File
@@ -0,0 +1,177 @@
This file is wait.def, from which is created wait.c.
It implements the builtin "wait" in Bash.
Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
$BUILTIN wait
$FUNCTION wait_builtin
$DEPENDS_ON JOB_CONTROL
$PRODUCES wait.c
$SHORT_DOC wait [n]
Wait for the specified process and report its termination status. If
N is not given, all currently active child processes are waited for,
and the return code is zero. N may be a process ID or a job
specification; if a job spec is given, all processes in the job's
pipeline are waited for.
$END
$BUILTIN wait
$FUNCTION wait_builtin
$DEPENDS_ON !JOB_CONTROL
$SHORT_DOC wait [n]
Wait for the specified process and report its termination status. If
N is not given, all currently active child processes are waited for,
and the return code is zero. N is a process ID; if it is not given,
all child processes of the shell are waited for.
$END
#include <config.h>
#include "../bashtypes.h"
#include <signal.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <chartypes.h>
#include "../bashansi.h"
#include "../shell.h"
#include "../jobs.h"
#include "common.h"
#include "bashgetopt.h"
extern int interrupt_immediately;
extern int wait_signal_received;
procenv_t wait_intr_buf;
/* Wait for the pid in LIST to stop or die. If no arguments are given, then
wait for all of the active background processes of the shell and return
0. If a list of pids or job specs are given, return the exit status of
the last one waited for. */
#define WAIT_RETURN(s) \
do \
{ \
interrupt_immediately = old_interrupt_immediately;\
return (s);\
} \
while (0)
int
wait_builtin (list)
WORD_LIST *list;
{
int status, code;
volatile int old_interrupt_immediately;
USE_VAR(list);
if (no_options (list))
return (EX_USAGE);
list = loptend;
old_interrupt_immediately = interrupt_immediately;
interrupt_immediately++;
/* POSIX.2 says: When the shell is waiting (by means of the wait utility)
for asynchronous commands to complete, the reception of a signal for
which a trap has been set shall cause the wait utility to return
immediately with an exit status greater than 128, after which the trap
associated with the signal shall be taken.
We handle SIGINT here; it's the only one that needs to be treated
specially (I think), since it's handled specially in {no,}jobs.c. */
code = setjmp (wait_intr_buf);
if (code)
{
status = 128 + wait_signal_received;
WAIT_RETURN (status);
}
/* We support jobs or pids.
wait <pid-or-job> [pid-or-job ...] */
/* But wait without any arguments means to wait for all of the shell's
currently active background processes. */
if (list == 0)
{
wait_for_background_pids ();
WAIT_RETURN (EXECUTION_SUCCESS);
}
status = EXECUTION_SUCCESS;
while (list)
{
pid_t pid;
char *w;
intmax_t pid_value;
w = list->word->word;
if (DIGIT (*w))
{
if (legal_number (w, &pid_value) && pid_value == (pid_t)pid_value)
{
pid = (pid_t)pid_value;
status = wait_for_single_pid (pid);
}
else
{
sh_badpid (w);
WAIT_RETURN (EXECUTION_FAILURE);
}
}
#if defined (JOB_CONTROL)
else if (*w && *w == '%')
/* Must be a job spec. Check it out. */
{
int job;
sigset_t set, oset;
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
if (INVALID_JOB (job))
{
if (job != DUP_JOB)
sh_badjob (list->word->word);
UNBLOCK_CHILD (oset);
status = 127; /* As per Posix.2, section 4.70.2 */
list = list->next;
continue;
}
/* Job spec used. Wait for the last pid in the pipeline. */
UNBLOCK_CHILD (oset);
status = wait_for_job (job);
}
#endif /* JOB_CONTROL */
else
{
sh_badpid (w);
status = EXECUTION_FAILURE;
}
list = list->next;
}
WAIT_RETURN (status);
}
-2
View File
@@ -52,8 +52,6 @@ extern int errno;
extern int executing_line_number __P((void));
extern int interactive_shell, interactive, startup_state;
extern char *dollar_vars[];
extern char *shell_name;
#if defined (JOB_CONTROL)
extern pid_t shell_pgrp;
+454
View File
@@ -0,0 +1,454 @@
/* error.c -- Functions for handling errors. */
/* Copyright (C) 1993-2003 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#include "config.h"
#include "bashtypes.h"
#include <fcntl.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if defined (PREFER_STDARG)
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#include <stdio.h>
#include <errno.h>
#if !defined (errno)
extern int errno;
#endif /* !errno */
#include "bashansi.h"
#include "bashintl.h"
#include "shell.h"
#include "flags.h"
#include "input.h"
#if defined (HISTORY)
# include "bashhist.h"
#endif
extern int executing_line_number __P((void));
extern int interactive_shell, interactive, startup_state;
extern char *dollar_vars[];
extern char *shell_name;
#if defined (JOB_CONTROL)
extern pid_t shell_pgrp;
extern int give_terminal_to __P((pid_t, int));
#endif /* JOB_CONTROL */
#if defined (ARRAY_VARS)
extern char *bash_badsub_errmsg;
#endif
static void error_prolog __P((int));
/* The current maintainer of the shell. You change this in the
Makefile. */
#if !defined (MAINTAINER)
#define MAINTAINER "bash-maintainers@gnu.org"
#endif
char *the_current_maintainer = MAINTAINER;
int gnu_error_format = 0;
static void
error_prolog (print_lineno)
int print_lineno;
{
char *ename;
int line;
ename = get_name_for_error ();
line = (print_lineno && interactive_shell == 0) ? executing_line_number () : -1;
if (line > 0)
fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : " line ", line);
else
fprintf (stderr, "%s: ", ename);
}
/* Return the name of the shell or the shell script for error reporting. */
char *
get_name_for_error ()
{
char *name;
#if defined (ARRAY_VARS)
SHELL_VAR *bash_source_v;
ARRAY *bash_source_a;
#endif
name = (char *)NULL;
if (interactive_shell == 0)
{
#if defined (ARRAY_VARS)
bash_source_v = find_variable ("BASH_SOURCE");
if (bash_source_v && array_p (bash_source_v) &&
(bash_source_a = array_cell (bash_source_v)))
name = array_reference (bash_source_a, 0);
if (name == 0)
#endif
name = dollar_vars[0];
}
if (name == 0 && shell_name && *shell_name)
name = base_pathname (shell_name);
if (name == 0)
#if defined (PROGRAM)
name = PROGRAM;
#else
name = "bash";
#endif
return (name);
}
/* Report an error having to do with FILENAME. This does not use
sys_error so the filename is not interpreted as a printf-style
format string. */
void
file_error (filename)
const char *filename;
{
report_error ("%s: %s", filename, strerror (errno));
}
void
#if defined (PREFER_STDARG)
programming_error (const char *format, ...)
#else
programming_error (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
char *h;
#if defined (JOB_CONTROL)
give_terminal_to (shell_pgrp, 0);
#endif /* JOB_CONTROL */
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
va_end (args);
#if defined (HISTORY)
if (remember_on_history)
{
h = last_history_line ();
fprintf (stderr, _("last command: %s\n"), h ? h : "(null)");
}
#endif
#if 0
fprintf (stderr, "Report this to %s\n", the_current_maintainer);
#endif
fprintf (stderr, _("Aborting..."));
fflush (stderr);
abort ();
}
/* Print an error message and, if `set -e' has been executed, exit the
shell. Used in this file by file_error and programming_error. Used
outside this file mostly to report substitution and expansion errors,
and for bad invocation options. */
void
#if defined (PREFER_STDARG)
report_error (const char *format, ...)
#else
report_error (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
error_prolog (1);
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
va_end (args);
if (exit_immediately_on_error)
exit_shell (1);
}
void
#if defined (PREFER_STDARG)
fatal_error (const char *format, ...)
#else
fatal_error (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
error_prolog (0);
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
va_end (args);
sh_exit (2);
}
void
#if defined (PREFER_STDARG)
internal_error (const char *format, ...)
#else
internal_error (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
error_prolog (1);
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
va_end (args);
}
void
#if defined (PREFER_STDARG)
internal_warning (const char *format, ...)
#else
internal_warning (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
fprintf (stderr, _("%s: warning: "), get_name_for_error ());
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
va_end (args);
}
void
#if defined (PREFER_STDARG)
sys_error (const char *format, ...)
#else
sys_error (format, va_alist)
const char *format;
va_dcl
#endif
{
int e;
va_list args;
e = errno;
error_prolog (0);
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, ": %s\n", strerror (e));
va_end (args);
}
/* An error from the parser takes the general form
shell_name: input file name: line number: message
The input file name and line number are omitted if the shell is
currently interactive. If the shell is not currently interactive,
the input file name is inserted only if it is different from the
shell name. */
void
#if defined (PREFER_STDARG)
parser_error (int lineno, const char *format, ...)
#else
parser_error (lineno, format, va_alist)
int lineno;
const char *format;
va_dcl
#endif
{
va_list args;
char *ename, *iname;
ename = get_name_for_error ();
iname = yy_input_name ();
if (interactive)
fprintf (stderr, "%s: ", ename);
else if (interactive_shell)
fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : " line ", lineno);
else if (STREQ (ename, iname))
fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : " line ", lineno);
else
fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : " line ", lineno);
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
va_end (args);
if (exit_immediately_on_error)
exit_shell (2);
}
#ifdef DEBUG
void
#if defined (PREFER_STDARG)
itrace (const char *format, ...)
#else
itrace (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
fprintf(stderr, "TRACE: pid %ld: ", (long)getpid());
SH_VA_START (args, format);
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
va_end (args);
fflush(stderr);
}
/* A trace function for silent debugging -- doesn't require a control
terminal. */
void
#if defined (PREFER_STDARG)
trace (const char *format, ...)
#else
trace (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
static FILE *tracefp = (FILE *)NULL;
if (tracefp == NULL)
tracefp = fopen("/tmp/bash-trace.log", "a+");
if (tracefp == NULL)
tracefp = stderr;
else
fcntl (fileno (tracefp), F_SETFD, 1); /* close-on-exec */
fprintf(tracefp, "TRACE: pid %ld: ", (long)getpid());
SH_VA_START (args, format);
vfprintf (tracefp, format, args);
fprintf (tracefp, "\n");
va_end (args);
fflush(tracefp);
}
#endif /* DEBUG */
/* **************************************************************** */
/* */
/* Common error reporting */
/* */
/* **************************************************************** */
static char *cmd_error_table[] = {
N_("unknown command error"), /* CMDERR_DEFAULT */
N_("bad command type"), /* CMDERR_BADTYPE */
N_("bad connector"), /* CMDERR_BADCONN */
N_("bad jump"), /* CMDERR_BADJUMP */
0
};
void
command_error (func, code, e, flags)
const char *func;
int code, e, flags; /* flags currently unused */
{
if (code > CMDERR_LAST)
code = CMDERR_DEFAULT;
programming_error ("%s: %s: %d", func, _(cmd_error_table[code]), e);
}
char *
command_errstr (code)
int code;
{
if (code > CMDERR_LAST)
code = CMDERR_DEFAULT;
return (_(cmd_error_table[code]));
}
#ifdef ARRAY_VARS
void
err_badarraysub (s)
const char *s;
{
report_error ("%s: %s", s, _(bash_badsub_errmsg));
}
#endif
void
err_unboundvar (s)
const char *s;
{
report_error (_("%s: unbound variable"), s);
}
void
err_readonly (s)
const char *s;
{
report_error (_("%s: readonly variable"), s);
}
+2 -1
View File
@@ -112,6 +112,7 @@ extern void set_default_locale __P((void));
extern void set_default_locale_vars __P((void));
extern int set_locale_var __P((char *, char *));
extern int set_lang __P((char *, char *));
extern void set_default_lang __P((void));
extern char *get_locale_var __P((char *));
extern char *localetrans __P((char *, int, int *));
extern char *mk_msgstr __P((char *, int *));
@@ -254,7 +255,7 @@ extern int strcasecmp __P((const char *, const char *));
#endif /* HAVE_STRCASECMP */
/* declarations for functions defined in lib/sh/strerror.c */
#if !defined (strerror)
#if !defined (HAVE_STRERROR) && !defined (strerror)
extern char *strerror __P((int));
#endif
+4
View File
@@ -112,6 +112,7 @@ extern void set_default_locale __P((void));
extern void set_default_locale_vars __P((void));
extern int set_locale_var __P((char *, char *));
extern int set_lang __P((char *, char *));
extern void set_default_lang __P((void));
extern char *get_locale_var __P((char *));
extern char *localetrans __P((char *, int, int *));
extern char *mk_msgstr __P((char *, int *));
@@ -225,6 +226,9 @@ extern char *sh_realpath __P((const char *, char *));
extern int sh_setlinebuf __P((FILE *));
#endif
/* declarations for functions defined in lib/sh/shaccess.c */
extern int sh_eaccess __P((char *, int));
/* declarations for functions defined in lib/sh/shmatch.c */
extern int sh_regmatch __P((const char *, const char *, int));
-1
View File
@@ -48,7 +48,6 @@ extern int errno;
#endif /* !errno */
extern int expand_aliases;
extern int interrupt_immediately;
extern int interactive_comments;
extern int check_hashed_filenames;
extern int source_uses_path;
+6 -1
View File
@@ -477,8 +477,13 @@ check_binary_file (sample, sample_len)
if (c == '\n')
return (0);
#if 0
if (ISSPACE (c) == 0 && ISPRINT (c) == 0)
#else
if (c == '\0')
#endif
return (1);
}
return (0);
@@ -503,7 +508,7 @@ int
file_iswdir (fn)
char *fn;
{
return (file_isdir (fn) && test_eaccess (fn, W_OK) == 0);
return (file_isdir (fn) && sh_eaccess (fn, W_OK) == 0);
}
/* Return 1 if STRING contains an absolute pathname, else 0. Used by `cd'
+2
View File
@@ -47,6 +47,8 @@
extern int errno;
#endif /* !errno */
extern void termsig_handler __P((int));
/* Functions to handle reading input on systems that don't restart read(2)
if a signal is received. */
+625
View File
@@ -0,0 +1,625 @@
/* input.c -- functions to perform buffered input with synchronization. */
/* Copyright (C) 1992 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#include "config.h"
#include "bashtypes.h"
#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#include "filecntl.h"
#include "posixstat.h"
#include <stdio.h>
#include <errno.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "bashansi.h"
#include "bashintl.h"
#include "command.h"
#include "general.h"
#include "input.h"
#include "error.h"
#include "externs.h"
#include "quit.h"
#if !defined (errno)
extern int errno;
#endif /* !errno */
/* Functions to handle reading input on systems that don't restart read(2)
if a signal is received. */
static char localbuf[128];
static int local_index = 0, local_bufused = 0;
/* Posix and USG systems do not guarantee to restart read () if it is
interrupted by a signal. We do the read ourselves, and restart it
if it returns EINTR. */
int
getc_with_restart (stream)
FILE *stream;
{
unsigned char uc;
CHECK_TERMSIG;
/* Try local buffering to reduce the number of read(2) calls. */
if (local_index == local_bufused || local_bufused == 0)
{
while (1)
{
CHECK_TERMSIG;
local_bufused = read (fileno (stream), localbuf, sizeof(localbuf));
if (local_bufused > 0)
break;
else if (local_bufused == 0 || errno != EINTR)
{
local_index = 0;
return EOF;
}
}
local_index = 0;
}
uc = localbuf[local_index++];
return uc;
}
int
ungetc_with_restart (c, stream)
int c;
FILE *stream;
{
if (local_index == 0 || c == EOF)
return EOF;
localbuf[--local_index] = c;
return c;
}
#if defined (BUFFERED_INPUT)
/* A facility similar to stdio, but input-only. */
#if defined (USING_BASH_MALLOC)
# define MAX_INPUT_BUFFER_SIZE 8176
#else
# define MAX_INPUT_BUFFER_SIZE 8192
#endif
#if !defined (SEEK_CUR)
# define SEEK_CUR 1
#endif /* !SEEK_CUR */
#ifdef max
# undef max
#endif
#define max(a, b) (((a) > (b)) ? (a) : (b))
#ifdef min
# undef min
#endif
#define min(a, b) ((a) > (b) ? (b) : (a))
extern int interactive_shell;
int bash_input_fd_changed;
/* This provides a way to map from a file descriptor to the buffer
associated with that file descriptor, rather than just the other
way around. This is needed so that buffers are managed properly
in constructs like 3<&4. buffers[x]->b_fd == x -- that is how the
correspondence is maintained. */
static BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL;
static int nbuffers;
#define ALLOCATE_BUFFERS(n) \
do { if ((n) >= nbuffers) allocate_buffers (n); } while (0)
/* Make sure `buffers' has at least N elements. */
static void
allocate_buffers (n)
int n;
{
register int i, orig_nbuffers;
orig_nbuffers = nbuffers;
nbuffers = n + 20;
buffers = (BUFFERED_STREAM **)xrealloc
(buffers, nbuffers * sizeof (BUFFERED_STREAM *));
/* Zero out the new buffers. */
for (i = orig_nbuffers; i < nbuffers; i++)
buffers[i] = (BUFFERED_STREAM *)NULL;
}
/* Construct and return a BUFFERED_STREAM corresponding to file descriptor
FD, using BUFFER. */
static BUFFERED_STREAM *
make_buffered_stream (fd, buffer, bufsize)
int fd;
char *buffer;
size_t bufsize;
{
BUFFERED_STREAM *bp;
bp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
ALLOCATE_BUFFERS (fd);
buffers[fd] = bp;
bp->b_fd = fd;
bp->b_buffer = buffer;
bp->b_size = bufsize;
bp->b_used = bp->b_inputp = bp->b_flag = 0;
if (bufsize == 1)
bp->b_flag |= B_UNBUFF;
return (bp);
}
/* Allocate a new BUFFERED_STREAM, copy BP to it, and return the new copy. */
static BUFFERED_STREAM *
copy_buffered_stream (bp)
BUFFERED_STREAM *bp;
{
BUFFERED_STREAM *nbp;
if (!bp)
return ((BUFFERED_STREAM *)NULL);
nbp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
xbcopy ((char *)bp, (char *)nbp, sizeof (BUFFERED_STREAM));
return (nbp);
}
int
set_bash_input_fd (fd)
int fd;
{
if (bash_input.type == st_bstream)
bash_input.location.buffered_fd = fd;
else if (interactive_shell == 0)
default_buffered_input = fd;
return 0;
}
int
fd_is_bash_input (fd)
int fd;
{
if (bash_input.type == st_bstream && bash_input.location.buffered_fd == fd)
return 1;
else if (interactive_shell == 0 && default_buffered_input == fd)
return 1;
return 0;
}
/* Save the buffered stream corresponding to file descriptor FD (which bash
is using to read input) to a buffered stream associated with NEW_FD. If
NEW_FD is -1, a new file descriptor is allocated with fcntl. The new
file descriptor is returned on success, -1 on error. */
int
save_bash_input (fd, new_fd)
int fd, new_fd;
{
int nfd;
/* Sync the stream so we can re-read from the new file descriptor. We
might be able to avoid this by copying the buffered stream verbatim
to the new file descriptor. */
if (buffers[fd])
sync_buffered_stream (fd);
/* Now take care of duplicating the file descriptor that bash is
using for input, so we can reinitialize it later. */
nfd = (new_fd == -1) ? fcntl (fd, F_DUPFD, 10) : new_fd;
if (nfd == -1)
{
if (fcntl (fd, F_GETFD, 0) == 0)
sys_error (_("cannot allocate new file descriptor for bash input from fd %d"), fd);
return -1;
}
if (buffers[nfd])
{
/* What's this? A stray buffer without an associated open file
descriptor? Free up the buffer and report the error. */
internal_error (_("save_bash_input: buffer already exists for new fd %d"), nfd);
free_buffered_stream (buffers[nfd]);
}
/* Reinitialize bash_input.location. */
if (bash_input.type == st_bstream)
{
bash_input.location.buffered_fd = nfd;
fd_to_buffered_stream (nfd);
close_buffered_fd (fd); /* XXX */
}
else
/* If the current input type is not a buffered stream, but the shell
is not interactive and therefore using a buffered stream to read
input (e.g. with an `eval exec 3>output' inside a script), note
that the input fd has been changed. pop_stream() looks at this
value and adjusts the input fd to the new value of
default_buffered_input accordingly. */
bash_input_fd_changed++;
if (default_buffered_input == fd)
default_buffered_input = nfd;
SET_CLOSE_ON_EXEC (nfd);
return nfd;
}
/* Check that file descriptor FD is not the one that bash is currently
using to read input from a script. FD is about to be duplicated onto,
which means that the kernel will close it for us. If FD is the bash
input file descriptor, we need to seek backwards in the script (if
possible and necessary -- scripts read from stdin are still unbuffered),
allocate a new file descriptor to use for bash input, and re-initialize
the buffered stream. Make sure the file descriptor used to save bash
input is set close-on-exec. Returns 0 on success, -1 on failure. This
works only if fd is > 0 -- if fd == 0 and bash is reading input from
fd 0, save_bash_input is used instead, to cooperate with input
redirection (look at redir.c:add_undo_redirect()). */
int
check_bash_input (fd)
int fd;
{
if (fd_is_bash_input (fd))
{
if (fd > 0)
return ((save_bash_input (fd, -1) == -1) ? -1 : 0);
else if (fd == 0)
return ((sync_buffered_stream (fd) == -1) ? -1 : 0);
}
return 0;
}
/* This is the buffered stream analogue of dup2(fd1, fd2). The
BUFFERED_STREAM corresponding to fd2 is deallocated, if one exists.
BUFFERS[fd1] is copied to BUFFERS[fd2]. This is called by the
redirect code for constructs like 4<&0 and 3</etc/rc.local. */
int
duplicate_buffered_stream (fd1, fd2)
int fd1, fd2;
{
int is_bash_input, m;
if (fd1 == fd2)
return 0;
m = max (fd1, fd2);
ALLOCATE_BUFFERS (m);
/* If FD2 is the file descriptor bash is currently using for shell input,
we need to do some extra work to make sure that the buffered stream
actually exists (it might not if fd1 was not active, and the copy
didn't actually do anything). */
is_bash_input = (bash_input.type == st_bstream) &&
(bash_input.location.buffered_fd == fd2);
if (buffers[fd2])
{
/* If the two objects share the same b_buffer, don't free it. */
if (buffers[fd1] && buffers[fd1]->b_buffer && buffers[fd1]->b_buffer == buffers[fd2]->b_buffer)
buffers[fd2] = (BUFFERED_STREAM *)NULL;
else
free_buffered_stream (buffers[fd2]);
}
buffers[fd2] = copy_buffered_stream (buffers[fd1]);
if (buffers[fd2])
buffers[fd2]->b_fd = fd2;
if (is_bash_input)
{
if (!buffers[fd2])
fd_to_buffered_stream (fd2);
buffers[fd2]->b_flag |= B_WASBASHINPUT;
}
return (fd2);
}
/* Return 1 if a seek on FD will succeed. */
#ifndef __CYGWIN__
# define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
#else
# define fd_is_seekable(fd) 0
#endif /* __CYGWIN__ */
/* Take FD, a file descriptor, and create and return a buffered stream
corresponding to it. If something is wrong and the file descriptor
is invalid, return a NULL stream. */
BUFFERED_STREAM *
fd_to_buffered_stream (fd)
int fd;
{
char *buffer;
size_t size;
struct stat sb;
if (fstat (fd, &sb) < 0)
{
close (fd);
return ((BUFFERED_STREAM *)NULL);
}
size = (fd_is_seekable (fd)) ? min (sb.st_size, MAX_INPUT_BUFFER_SIZE) : 1;
if (size == 0)
size = 1;
buffer = (char *)xmalloc (size);
return (make_buffered_stream (fd, buffer, size));
}
/* Return a buffered stream corresponding to FILE, a file name. */
BUFFERED_STREAM *
open_buffered_stream (file)
char *file;
{
int fd;
fd = open (file, O_RDONLY);
return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL);
}
/* Deallocate a buffered stream and free up its resources. Make sure we
zero out the slot in BUFFERS that points to BP. */
void
free_buffered_stream (bp)
BUFFERED_STREAM *bp;
{
int n;
if (!bp)
return;
n = bp->b_fd;
if (bp->b_buffer)
free (bp->b_buffer);
free (bp);
buffers[n] = (BUFFERED_STREAM *)NULL;
}
/* Close the file descriptor associated with BP, a buffered stream, and free
up the stream. Return the status of closing BP's file descriptor. */
int
close_buffered_stream (bp)
BUFFERED_STREAM *bp;
{
int fd;
if (!bp)
return (0);
fd = bp->b_fd;
free_buffered_stream (bp);
return (close (fd));
}
/* Deallocate the buffered stream associated with file descriptor FD, and
close FD. Return the status of the close on FD. */
int
close_buffered_fd (fd)
int fd;
{
if (fd < 0)
{
errno = EBADF;
return -1;
}
if (fd >= nbuffers || !buffers || !buffers[fd])
return (close (fd));
return (close_buffered_stream (buffers[fd]));
}
/* Make the BUFFERED_STREAM associcated with buffers[FD] be BP, and return
the old BUFFERED_STREAM. */
BUFFERED_STREAM *
set_buffered_stream (fd, bp)
int fd;
BUFFERED_STREAM *bp;
{
BUFFERED_STREAM *ret;
ret = buffers[fd];
buffers[fd] = bp;
return ret;
}
/* Read a buffer full of characters from BP, a buffered stream. */
static int
b_fill_buffer (bp)
BUFFERED_STREAM *bp;
{
ssize_t nr;
CHECK_TERMSIG;
nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
if (nr <= 0)
{
bp->b_used = 0;
bp->b_buffer[0] = 0;
if (nr == 0)
bp->b_flag |= B_EOF;
else
bp->b_flag |= B_ERROR;
return (EOF);
}
#if defined (__CYGWIN__)
/* If on cygwin, translate \r\n to \n. */
if (nr >= 2 && bp->b_buffer[nr - 2] == '\r' && bp->b_buffer[nr - 1] == '\n')
{
bp->b_buffer[nr - 2] = '\n';
nr--;
}
#endif
bp->b_used = nr;
bp->b_inputp = 0;
return (bp->b_buffer[bp->b_inputp++] & 0xFF);
}
/* Get a character from buffered stream BP. */
#define bufstream_getc(bp) \
(bp->b_inputp == bp->b_used || !bp->b_used) \
? b_fill_buffer (bp) \
: bp->b_buffer[bp->b_inputp++] & 0xFF
/* Push C back onto buffered stream BP. */
static int
bufstream_ungetc(c, bp)
int c;
BUFFERED_STREAM *bp;
{
if (c == EOF || bp->b_inputp == 0)
return (EOF);
bp->b_buffer[--bp->b_inputp] = c;
return (c);
}
/* Seek backwards on file BFD to synchronize what we've read so far
with the underlying file pointer. */
int
sync_buffered_stream (bfd)
int bfd;
{
BUFFERED_STREAM *bp;
off_t chars_left;
if (buffers == 0 || (bp = buffers[bfd]) == 0)
return (-1);
chars_left = bp->b_used - bp->b_inputp;
if (chars_left)
lseek (bp->b_fd, -chars_left, SEEK_CUR);
bp->b_used = bp->b_inputp = 0;
return (0);
}
int
buffered_getchar ()
{
CHECK_TERMSIG;
#if !defined (DJGPP)
return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
#else
/* On DJGPP, ignore \r. */
int ch;
while ((ch = bufstream_getc (buffers[bash_input.location.buffered_fd])) == '\r')
;
return ch;
#endif
}
int
buffered_ungetchar (c)
int c;
{
return (bufstream_ungetc (c, buffers[bash_input.location.buffered_fd]));
}
/* Make input come from file descriptor BFD through a buffered stream. */
void
with_input_from_buffered_stream (bfd, name)
int bfd;
char *name;
{
INPUT_STREAM location;
BUFFERED_STREAM *bp;
location.buffered_fd = bfd;
/* Make sure the buffered stream exists. */
bp = fd_to_buffered_stream (bfd);
init_yy_io (bp == 0 ? return_EOF : buffered_getchar,
buffered_ungetchar, st_bstream, name, location);
}
#if defined (TEST)
void *
xmalloc(s)
int s;
{
return (malloc (s));
}
void *
xrealloc(s, size)
char *s;
int size;
{
if (!s)
return(malloc (size));
else
return(realloc (s, size));
}
void
init_yy_io ()
{
}
process(bp)
BUFFERED_STREAM *bp;
{
int c;
while ((c = bufstream_getc(bp)) != EOF)
putchar(c);
}
BASH_INPUT bash_input;
struct stat dsb; /* can be used from gdb */
/* imitate /bin/cat */
main(argc, argv)
int argc;
char **argv;
{
register int i;
BUFFERED_STREAM *bp;
if (argc == 1) {
bp = fd_to_buffered_stream (0);
process(bp);
exit(0);
}
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-' && argv[i][1] == '\0') {
bp = fd_to_buffered_stream (0);
if (!bp)
continue;
process(bp);
free_buffered_stream (bp);
} else {
bp = open_buffered_stream (argv[i]);
if (!bp)
continue;
process(bp);
close_buffered_stream (bp);
}
}
exit(0);
}
#endif /* TEST */
#endif /* BUFFERED_INPUT */
+5 -7
View File
@@ -142,7 +142,6 @@ typedef int sh_job_map_func_t __P((JOB *, int, int, int));
/* Variables used here but defined in other files. */
extern int subshell_environment, line_number;
extern int posixly_correct, shell_level;
extern int interrupt_immediately;
extern int last_command_exit_value, last_command_exit_signal;
extern int loop_level, breaking;
extern int sourcelevel;
@@ -761,7 +760,7 @@ bgp_search (pid)
static void
bgp_prune ()
{
struct pidstat *ps, *p;
struct pidstat *ps;
while (bgpids.npid > js.c_childmax)
{
@@ -975,8 +974,7 @@ delete_job (job_index, dflags)
{
register JOB *temp;
PROCESS *proc;
int ndel, status;
pid_t pid;
int ndel;
if (js.j_jobslots == 0 || jobs_list_frozen)
return;
@@ -2827,14 +2825,14 @@ start_job (job, foreground)
if (foreground)
{
pid_t pid;
int s;
int st;
pid = find_last_pid (job, 0);
UNBLOCK_CHILD (oset);
s = wait_for (pid);
st = wait_for (pid);
shell_tty_info = save_stty;
set_tty_state ();
return (s);
return (st);
}
else
{
+2 -7
View File
@@ -142,7 +142,6 @@ typedef int sh_job_map_func_t __P((JOB *, int, int, int));
/* Variables used here but defined in other files. */
extern int subshell_environment, line_number;
extern int posixly_correct, shell_level;
extern int interrupt_immediately;
extern int last_command_exit_value, last_command_exit_signal;
extern int loop_level, breaking;
extern int sourcelevel;
@@ -761,7 +760,7 @@ bgp_search (pid)
static void
bgp_prune ()
{
struct pidstat *ps, *p;
struct pidstat *ps;
while (bgpids.npid > js.c_childmax)
{
@@ -975,8 +974,7 @@ delete_job (job_index, dflags)
{
register JOB *temp;
PROCESS *proc;
int ndel, status;
pid_t pid;
int ndel;
if (js.j_jobslots == 0 || jobs_list_frozen)
return;
@@ -1079,7 +1077,6 @@ add_process (name, pid)
{
PROCESS *t, *p;
itrace("add_process: name = %s running_trap = %d", name, running_trap);
#if defined (RECYCLES_PIDS)
int j;
p = find_process (pid, 0, &j);
@@ -1670,7 +1667,6 @@ make_child (command, async_p)
sigemptyset (&oset);
sigprocmask (SIG_BLOCK, &set, &oset);
itrace("make_child: command = %s", command ? command : "");
making_children ();
#if defined (BUFFERED_INPUT)
@@ -3436,7 +3432,6 @@ notify_of_job_status ()
fprintf (stderr, "\n");
if (dir == 0)
dir = current_working_directory ();
itrace("calling pretty_print_job for job %d", job);
pretty_print_job (job, JLIST_STANDARD, stderr);
if (dir && (strcmp (dir, jobs[job]->wd) != 0))
fprintf (stderr,
+1 -1
View File
@@ -184,7 +184,7 @@ mbskipname (pat, dname)
{
int ret;
wchar_t *pat_wc, *dn_wc;
size_t pat_n, dn_n, n;
size_t pat_n, dn_n;
pat_n = xdupmbstowcs (&pat_wc, NULL, pat);
dn_n = xdupmbstowcs (&dn_wc, NULL, dname);
-1
View File
@@ -247,7 +247,6 @@ rangecmp_wc (c1, c2)
{
static wchar_t s1[2] = { L' ', L'\0' };
static wchar_t s2[2] = { L' ', L'\0' };
int ret;
if (c1 == c2)
return 0;
-1
View File
@@ -1537,7 +1537,6 @@ rl_variable_value (name)
const char *name;
{
register int i;
int v;
/* Check for simple variables first. */
i = find_boolean_var (name);
+2 -2
View File
@@ -1104,7 +1104,8 @@ compute_lcd_of_matches (match_list, matches, text)
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
{
mbstate_t ps_back = ps1;
mbstate_t ps_back;
ps_back = ps1;
if (!_rl_compare_chars (match_list[i], si, &ps1, match_list[i+1], si, &ps2))
break;
else if ((v = _rl_get_char_len (&match_list[i][si], &ps_back)) > 1)
@@ -1896,7 +1897,6 @@ rl_filename_completion_function (text, state)
static char *filename = (char *)NULL;
static char *dirname = (char *)NULL;
static char *users_dirname = (char *)NULL;
static char *orig_filename = (char *)NULL;
static int filename_len;
char *temp;
int dirlen;
+2 -21
View File
@@ -950,7 +950,7 @@ gen_completion_matches (text, start, end, our_func, found_quote, quote_char)
rl_compentry_func_t *our_func;
int found_quote, quote_char;
{
char **matches, *temp;
char **matches;
rl_completion_found_quote = found_quote;
rl_completion_quote_character = quote_char;
@@ -969,28 +969,9 @@ gen_completion_matches (text, start, end, our_func, found_quote, quote_char)
}
}
/* Beware -- we're stripping the quotes here. Do this only if we know
we are doing filename completion and the application has defined a
filename dequoting function. */
/* XXX -- can move this into rl_filename_completion_function and use
rl_completion_found_quote and rl_completion_quote_char. Should be
after the directory rewriting hook and maybe the directory completion
hook. Also need to change bash_directory_expansion in the same way
as rl_filename_completion_function. */
temp = (char *)NULL;
#if 0
if (found_quote && our_func == rl_filename_completion_function &&
rl_filename_dequoting_function)
{
/* delete single and double quotes */
temp = (*rl_filename_dequoting_function) (text, quote_char);
text = temp; /* not freeing text is not a memory leak */
}
#endif
/* XXX -- filename dequoting moved into rl_filename_completion_function */
matches = rl_completion_matches (text, our_func);
FREE (temp);
return matches;
}
+3 -1
View File
@@ -2365,12 +2365,14 @@ _rl_col_width (str, start, end)
int start, end;
{
wchar_t wc;
mbstate_t ps = {0};
mbstate_t ps;
int tmp, point, width, max;
if (end <= start)
return 0;
memset (&ps, 0, sizeof (mbstate_t));
point = 0;
max = end;
+44 -38
View File
@@ -1,6 +1,6 @@
/* display.c -- readline redisplay facility. */
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
/* Copyright (C) 1987-2006 Free Software Foundation, Inc.
This file is part of the GNU Readline Library, a library for
reading lines of text with interactive input and history editing.
@@ -59,10 +59,6 @@
extern char *strchr (), *strrchr ();
#endif /* !strchr && !__STDC__ */
#if defined (HACK_TERMCAP_MOTION)
extern char *_rl_term_forward_char;
#endif
static void update_line PARAMS((char *, char *, int, int, int, int));
static void space_to_eol PARAMS((int));
static void delete_chars PARAMS((int));
@@ -80,7 +76,8 @@ static int *inv_lbreaks, *vis_lbreaks;
static int inv_lbsize, vis_lbsize;
/* Heuristic used to decide whether it is faster to move from CUR to NEW
by backing up or outputting a carriage return and moving forward. */
by backing up or outputting a carriage return and moving forward. CUR
and NEW are either both buffer positions or absolute screen positions. */
#define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new)))
/* _rl_last_c_pos is an absolute cursor position in multibyte locales and a
@@ -143,6 +140,7 @@ int _rl_last_c_pos = 0;
int _rl_last_v_pos = 0;
static int cpos_adjusted;
static int cpos_buffer_position;
/* Number of lines currently on screen minus 1. */
int _rl_vis_botlin = 0;
@@ -460,7 +458,7 @@ rl_redisplay ()
{
register int in, out, c, linenum, cursor_linenum;
register char *line;
int c_pos, inv_botlin, lb_botlin, lb_linenum, o_cpos;
int inv_botlin, lb_botlin, lb_linenum, o_cpos;
int newlines, lpos, temp, modmark, n0, num;
char *prompt_this_line;
#if defined (HANDLE_MULTIBYTE)
@@ -484,7 +482,7 @@ rl_redisplay ()
}
/* Draw the line into the buffer. */
c_pos = -1;
cpos_buffer_position = -1;
line = invisible_line;
out = inv_botlin = 0;
@@ -666,7 +664,7 @@ rl_redisplay ()
prompt_last_screen_line = newlines;
/* Draw the rest of the line (after the prompt) into invisible_line, keeping
track of where the cursor is (c_pos), the number of the line containing
track of where the cursor is (cpos_buffer_position), the number of the line containing
the cursor (lb_linenum), the last line number (lb_botlin and inv_botlin).
It maintains an array of line breaks for display (inv_lbreaks).
This handles expanding tabs for display and displaying meta characters. */
@@ -719,7 +717,7 @@ rl_redisplay ()
if (in == rl_point)
{
c_pos = out;
cpos_buffer_position = out;
lb_linenum = newlines;
}
@@ -813,7 +811,7 @@ rl_redisplay ()
}
if (in == rl_point)
{
c_pos = out;
cpos_buffer_position = out;
lb_linenum = newlines;
}
for (i = in; i < in+wc_bytes; i++)
@@ -844,9 +842,9 @@ rl_redisplay ()
}
line[out] = '\0';
if (c_pos < 0)
if (cpos_buffer_position < 0)
{
c_pos = out;
cpos_buffer_position = out;
lb_linenum = newlines;
}
@@ -855,7 +853,7 @@ rl_redisplay ()
inv_lbreaks[newlines+1] = out;
cursor_linenum = lb_linenum;
/* C_POS == position in buffer where cursor should be placed.
/* CPOS_BUFFER_POSITION == position in buffer where cursor should be placed.
CURSOR_LINENUM == line number where the cursor should be placed. */
/* PWP: now is when things get a bit hairy. The visible and invisible
@@ -1011,7 +1009,7 @@ rl_redisplay ()
pos = inv_lbreaks[cursor_linenum];
/* nleft == number of characters in the line buffer between the
start of the line and the desired cursor position. */
nleft = c_pos - pos;
nleft = cpos_buffer_position - pos;
/* NLEFT is now a number of characters in a buffer. When in a
multibyte locale, however, _rl_last_c_pos is an absolute cursor
@@ -1057,11 +1055,11 @@ rl_redisplay ()
will be LMARGIN. */
/* The number of characters that will be displayed before the cursor. */
ndisp = c_pos - wrap_offset;
ndisp = cpos_buffer_position - wrap_offset;
nleft = prompt_visible_length + wrap_offset;
/* Where the new cursor position will be on the screen. This can be
longer than SCREENWIDTH; if it is, lmargin will be adjusted. */
phys_c_pos = c_pos - (last_lmargin ? last_lmargin : wrap_offset);
phys_c_pos = cpos_buffer_position - (last_lmargin ? last_lmargin : wrap_offset);
t = _rl_screenwidth / 3;
/* If the number of characters had already exceeded the screenwidth,
@@ -1072,7 +1070,7 @@ rl_redisplay ()
two-thirds of the way across the screen. */
if (phys_c_pos > _rl_screenwidth - 2)
{
lmargin = c_pos - (2 * t);
lmargin = cpos_buffer_position - (2 * t);
if (lmargin < 0)
lmargin = 0;
/* If the left margin would be in the middle of a prompt with
@@ -1086,7 +1084,7 @@ rl_redisplay ()
{
/* If we are moving back towards the beginning of the line and
the last margin is no longer correct, compute a new one. */
lmargin = ((c_pos - 1) / t) * t; /* XXX */
lmargin = ((cpos_buffer_position - 1) / t) * t; /* XXX */
if (wrap_offset && lmargin > 0 && lmargin < nleft)
lmargin = nleft;
}
@@ -1131,7 +1129,7 @@ rl_redisplay ()
if (visible_first_line_len > _rl_screenwidth)
visible_first_line_len = _rl_screenwidth;
_rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]);
_rl_move_cursor_relative (cpos_buffer_position - lmargin, &invisible_line[lmargin]);
last_lmargin = lmargin;
}
}
@@ -1724,13 +1722,12 @@ _rl_move_cursor_relative (new, data)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
{
dpos = _rl_col_width (data, 0, new);
#if 0
if (dpos > woff)
#else
if (dpos > prompt_last_invisible)
#endif
if (dpos > prompt_last_invisible) /* XXX - don't use woff here */
{
dpos -= woff;
/* Since this will be assigned to _rl_last_c_pos at the end (more
precisely, _rl_last_c_pos == dpos when this function returns),
let the caller know. */
cpos_adjusted = 1;
}
}
@@ -1751,7 +1748,7 @@ _rl_move_cursor_relative (new, data)
else
#endif
i = _rl_last_c_pos - woff;
if (new == 0 || CR_FASTER (new, _rl_last_c_pos) ||
if (dpos == 0 || CR_FASTER (dpos, _rl_last_c_pos) ||
(_rl_term_autowrap && i == _rl_screenwidth))
{
#if defined (__MSDOS__)
@@ -1773,19 +1770,27 @@ _rl_move_cursor_relative (new, data)
sequence telling the terminal to move forward one character.
That kind of control is for people who don't know what the
data is underneath the cursor. */
#if defined (HACK_TERMCAP_MOTION)
if (_rl_term_forward_char)
{
for (i = cpos; i < dpos; i++)
tputs (_rl_term_forward_char, 1, _rl_output_character_function);
}
else
#endif /* HACK_TERMCAP_MOTION */
/* However, we need a handle on where the current display position is
in the buffer for the immediately preceding comment to be true.
In multibyte locales, we don't currently have that info available.
Without it, we don't know where the data we have to display begins
in the buffer and we have to go back to the beginning of the screen
line. In this case, we can use the terminal sequence to move forward
if it's available. */
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
{
tputs (_rl_term_cr, 1, _rl_output_character_function);
for (i = 0; i < new; i++)
putc (data[i], rl_outstream);
if (_rl_term_forward_char)
{
for (i = cpos; i < dpos; i++)
tputs (_rl_term_forward_char, 1, _rl_output_character_function);
}
else
{
tputs (_rl_term_cr, 1, _rl_output_character_function);
for (i = 0; i < new; i++)
putc (data[i], rl_outstream);
}
}
else
for (i = cpos; i < new; i++)
@@ -2213,7 +2218,8 @@ _rl_update_final ()
char *last_line;
last_line = &visible_line[vis_lbreaks[_rl_vis_botlin]];
_rl_move_cursor_relative (_rl_screenwidth - 1, last_line);
cpos_buffer_position = -1; /* don't know where we are in buffer */
_rl_move_cursor_relative (_rl_screenwidth - 1, last_line); /* XXX */
_rl_clear_to_eol (0);
putc (last_line[_rl_screenwidth - 1], rl_outstream);
}
+6 -6
View File
@@ -56,8 +56,6 @@
typedef int _hist_search_func_t PARAMS((const char *, int));
extern int rl_byte_oriented; /* declared in mbutil.c */
static char error_pointer;
static char *subst_lhs;
@@ -564,12 +562,12 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
{
int c, l;
int ch, l;
l = _rl_find_prev_mbchar (string, i, MB_FIND_ANY);
c = string[l];
ch = string[l];
/* XXX - original patch had i - 1 ??? If i == 0 it would fail. */
if (i && (c == '\'' || c == '"'))
quoted_search_delimiter = c;
if (i && (ch == '\'' || ch == '"'))
quoted_search_delimiter = ch;
}
else
#endif /* HANDLE_MULTIBYTE */
@@ -1430,6 +1428,8 @@ history_tokenize_word (string, ind)
{
if (peek == '<' && string[i + 2] == '-')
i++;
else if (peek == '<' && string[i + 2] == '<')
i++;
i += 2;
return i;
}
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -550,21 +550,21 @@ _rl_read_mbchar (mbchar, size)
}
/* Read a multibyte-character string whose first character is FIRST into
the buffer MB of length MBLEN. Returns the last character read, which
the buffer MB of length MLEN. Returns the last character read, which
may be FIRST. Used by the search functions, among others. Very similar
to _rl_read_mbchar. */
int
_rl_read_mbstring (first, mb, mblen)
_rl_read_mbstring (first, mb, mlen)
int first;
char *mb;
int mblen;
int mlen;
{
int i, c;
mbstate_t ps;
c = first;
memset (mb, 0, mblen);
for (i = 0; i < mblen; i++)
memset (mb, 0, mlen);
for (i = 0; i < mlen; i++)
{
mb[i] = (char)c;
memset (&ps, 0, sizeof (mbstate_t));
+14 -1
View File
@@ -179,6 +179,7 @@ rl_gather_tyi ()
struct timeval timeout;
#endif
chars_avail = 0;
tty = fileno (rl_instream);
#if defined (HAVE_SELECT)
@@ -220,6 +221,13 @@ rl_gather_tyi ()
}
#endif /* O_NDELAY */
#if defined (__MINGW32__)
/* Use getch/_kbhit to check for available console input, in the same way
that we read it normally. */
chars_avail = isatty (tty) ? _kbhit () : 0;
result = 0;
#endif
/* If there's nothing available, don't waste time trying to read
something. */
if (chars_avail <= 0)
@@ -263,7 +271,7 @@ rl_set_keyboard_input_timeout (u)
int o;
o = _keyboard_input_timeout;
if (u > 0)
if (u >= 0)
_keyboard_input_timeout = u;
return (o);
}
@@ -303,6 +311,11 @@ _rl_input_available ()
return (chars_avail);
#endif
#endif
#if defined (__MINGW32__)
if (isatty (tty))
return (_kbhit ());
#endif
return 0;
+8 -8
View File
@@ -1237,8 +1237,8 @@ rl_change_case (count, op)
#if defined (HANDLE_MULTIBYTE)
wchar_t wc, nwc;
char mb[MB_LEN_MAX+1];
int mblen;
mbstate_t ps;
int mlen;
mbstate_t mps;
#endif
start = rl_point;
@@ -1255,7 +1255,7 @@ rl_change_case (count, op)
SWAP (start, end);
#if defined (HANDLE_MULTIBYTE)
memset (&ps, 0, sizeof (mbstate_t));
memset (&mps, 0, sizeof (mbstate_t));
#endif
/* We are going to modify some text, so let's prepare to undo it. */
@@ -1290,15 +1290,15 @@ rl_change_case (count, op)
#if defined (HANDLE_MULTIBYTE)
else
{
mbrtowc (&wc, rl_line_buffer + start, end - start, &ps);
mbrtowc (&wc, rl_line_buffer + start, end - start, &mps);
nwc = (nop == UpCase) ? _rl_to_wupper (wc) : _rl_to_wlower (wc);
if (nwc != wc) /* just skip unchanged characters */
{
mblen = wcrtomb (mb, nwc, &ps);
if (mblen > 0)
mb[mblen] = '\0';
mlen = wcrtomb (mb, nwc, &mps);
if (mlen > 0)
mb[mlen] = '\0';
/* Assume the same width */
strncpy (rl_line_buffer + start, mb, mblen);
strncpy (rl_line_buffer + start, mb, mlen);
}
}
#endif
+5 -5
View File
@@ -1237,8 +1237,8 @@ rl_change_case (count, op)
#if defined (HANDLE_MULTIBYTE)
wchar_t wc, nwc;
char mb[MB_LEN_MAX+1];
int mblen, p;
mbstate_t ps;
int mblen;
mbstate_t mps;
#endif
start = rl_point;
@@ -1255,7 +1255,7 @@ rl_change_case (count, op)
SWAP (start, end);
#if defined (HANDLE_MULTIBYTE)
memset (&ps, 0, sizeof (mbstate_t));
memset (&mps, 0, sizeof (mbstate_t));
#endif
/* We are going to modify some text, so let's prepare to undo it. */
@@ -1290,11 +1290,11 @@ rl_change_case (count, op)
#if defined (HANDLE_MULTIBYTE)
else
{
mbrtowc (&wc, rl_line_buffer + start, end - start, &ps);
mbrtowc (&wc, rl_line_buffer + start, end - start, &mps);
nwc = (nop == UpCase) ? _rl_to_wupper (wc) : _rl_to_wlower (wc);
if (nwc != wc) /* just skip unchanged characters */
{
mblen = wcrtomb (mb, nwc, &ps);
mblen = wcrtomb (mb, nwc, &mps);
if (mblen > 0)
mb[mblen] = '\0';
/* Assume the same width */
+7 -7
View File
@@ -738,7 +738,7 @@ _rl_vi_change_mbchar_case (count)
{
wchar_t wc;
char mb[MB_LEN_MAX+1];
int mblen, p;
int mlen, p;
mbstate_t ps;
memset (&ps, 0, sizeof (mbstate_t));
@@ -762,9 +762,9 @@ _rl_vi_change_mbchar_case (count)
if (wc)
{
p = rl_point;
mblen = wcrtomb (mb, wc, &ps);
if (mblen >= 0)
mb[mblen] = '\0';
mlen = wcrtomb (mb, wc, &ps);
if (mlen >= 0)
mb[mlen] = '\0';
rl_begin_undo_group ();
rl_vi_delete (1, 0);
if (rl_point < p) /* Did we retreat at EOL? */
@@ -1457,9 +1457,9 @@ _rl_vi_change_char (count, c, mb)
}
static int
_rl_vi_callback_getchar (mb, mblen)
_rl_vi_callback_getchar (mb, mlen)
char *mb;
int mblen;
int mlen;
{
int c;
@@ -1469,7 +1469,7 @@ _rl_vi_callback_getchar (mb, mblen)
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
c = _rl_read_mbstring (c, mb, mblen);
c = _rl_read_mbstring (c, mb, mlen);
#endif
return c;
+4 -4
View File
@@ -653,7 +653,7 @@ _rl_vi_save_insert (up)
{
int len, start, end;
if (up == 0)
if (up == 0 || up->what != UNDO_INSERT)
{
if (vi_insert_buffer_size >= 1)
vi_insert_buffer[0] = '\0';
@@ -1457,9 +1457,9 @@ _rl_vi_change_char (count, c, mb)
}
static int
_rl_vi_callback_getchar (mb, mblen)
_rl_vi_callback_getchar (mb, mlen)
char *mb;
int mblen;
int mlen;
{
int c;
@@ -1469,7 +1469,7 @@ _rl_vi_callback_getchar (mb, mblen)
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
c = _rl_read_mbstring (c, mb, mblen);
c = _rl_read_mbstring (c, mb, mlen);
#endif
return c;
+10
View File
@@ -66,6 +66,16 @@ extern int errno;
extern int inet_aton __P((const char *, struct in_addr *));
#endif
#ifndef HAVE_GETADDRINFO
static int _getaddr __P((char *, struct in_addr));
static int _getserv __P((char *, int, unsigned short));
static int _netopen4 __P((char *, char *, int));
#else /* HAVE_GETADDRINFO */
static int _netopen6 __P((char *, char *, int));
#endif
static int _netopen __P((char *, char *, int));
#ifndef HAVE_GETADDRINFO
/* Stuff the internet address corresponding to HOST into AP, in network
byte order. Return 1 on success, 0 on failure. */
+340
View File
@@ -0,0 +1,340 @@
/*
* netopen.c -- functions to make tcp/udp connections
*
* Chet Ramey
* chet@ins.CWRU.Edu
*/
/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Bash is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with Bash; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#include <config.h>
#if defined (HAVE_NETWORK)
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#if defined (HAVE_SYS_SOCKET_H)
# include <sys/socket.h>
#endif
#if defined (HAVE_NETINET_IN_H)
# include <netinet/in.h>
#endif
#if defined (HAVE_NETDB_H)
# include <netdb.h>
#endif
#if defined (HAVE_ARPA_INET_H)
# include <arpa/inet.h>
#endif
#include <bashansi.h>
#include <bashintl.h>
#include <errno.h>
#include <shell.h>
#include <xmalloc.h>
#ifndef errno
extern int errno;
#endif
#if !defined (HAVE_INET_ATON)
extern int inet_aton __P((const char *, struct in_addr *));
#endif
#ifndef HAVE_GETADDRINFO
/* Stuff the internet address corresponding to HOST into AP, in network
byte order. Return 1 on success, 0 on failure. */
static int
_getaddr (host, ap)
char *host;
struct in_addr *ap;
{
struct hostent *h;
int r;
r = 0;
if (host[0] >= '0' && host[0] <= '9')
{
/* If the first character is a digit, guess that it's an
Internet address and return immediately if inet_aton succeeds. */
r = inet_aton (host, ap);
if (r)
return r;
}
#if !defined (HAVE_GETHOSTBYNAME)
return 0;
#else
h = gethostbyname (host);
if (h && h->h_addr)
{
bcopy(h->h_addr, (char *)ap, h->h_length);
return 1;
}
#endif
return 0;
}
/* Return 1 if SERV is a valid port number and stuff the converted value into
PP in network byte order. */
static int
_getserv (serv, proto, pp)
char *serv;
int proto;
unsigned short *pp;
{
intmax_t l;
unsigned short s;
if (legal_number (serv, &l))
{
s = (unsigned short)(l & 0xFFFF);
if (s != l)
return (0);
s = htons (s);
if (pp)
*pp = s;
return 1;
}
else
#if defined (HAVE_GETSERVBYNAME)
{
struct servent *se;
se = getservbyname (serv, (proto == 't') ? "tcp" : "udp");
if (se == 0)
return 0;
if (pp)
*pp = se->s_port; /* ports returned in network byte order */
return 1;
}
#else /* !HAVE_GETSERVBYNAME */
return 0;
#endif /* !HAVE_GETSERVBYNAME */
}
/*
* Open a TCP or UDP connection to HOST on port SERV. Uses the
* traditional BSD mechanisms. Returns the connected socket or -1 on error.
*/
static int
_netopen4(host, serv, typ)
char *host, *serv;
int typ;
{
struct in_addr ina;
struct sockaddr_in sin;
unsigned short p;
int s, e;
if (_getaddr(host, &ina) == 0)
{
internal_error (_("%s: host unknown"), host);
errno = EINVAL;
return -1;
}
if (_getserv(serv, typ, &p) == 0)
{
internal_error(_("%s: invalid service"), serv);
errno = EINVAL;
return -1;
}
memset ((char *)&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = p;
sin.sin_addr = ina;
s = socket(AF_INET, (typ == 't') ? SOCK_STREAM : SOCK_DGRAM, 0);
if (s < 0)
{
sys_error ("socket");
return (-1);
}
if (connect (s, (struct sockaddr *)&sin, sizeof (sin)) < 0)
{
e = errno;
sys_error("connect");
close(s);
errno = e;
return (-1);
}
return(s);
}
#endif /* ! HAVE_GETADDRINFO */
#ifdef HAVE_GETADDRINFO
/*
* Open a TCP or UDP connection to HOST on port SERV. Uses getaddrinfo(3)
* which provides support for IPv6. Returns the connected socket or -1
* on error.
*/
static int
_netopen6 (host, serv, typ)
char *host, *serv;
int typ;
{
int s, e;
struct addrinfo hints, *res, *res0;
int gerr;
memset ((char *)&hints, 0, sizeof (hints));
/* XXX -- if problems with IPv6, set to PF_INET for IPv4 only */
#ifdef DEBUG /* PF_INET is the one that works for me */
hints.ai_family = PF_INET;
#else
hints.ai_family = PF_UNSPEC;
#endif
hints.ai_socktype = (typ == 't') ? SOCK_STREAM : SOCK_DGRAM;
gerr = getaddrinfo (host, serv, &hints, &res0);
if (gerr)
{
if (gerr == EAI_SERVICE)
internal_error ("%s: %s", serv, gai_strerror (gerr));
else
internal_error ("%s: %s", host, gai_strerror (gerr));
errno = EINVAL;
return -1;
}
for (res = res0; res; res = res->ai_next)
{
if ((s = socket (res->ai_family, res->ai_socktype, res->ai_protocol)) < 0)
{
if (res->ai_next)
continue;
sys_error ("socket");
freeaddrinfo (res0);
return -1;
}
if (connect (s, res->ai_addr, res->ai_addrlen) < 0)
{
if (res->ai_next)
{
close (s);
continue;
}
e = errno;
sys_error ("connect");
close (s);
freeaddrinfo (res0);
errno = e;
return -1;
}
freeaddrinfo (res0);
break;
}
return s;
}
#endif /* HAVE_GETADDRINFO */
/*
* Open a TCP or UDP connection to HOST on port SERV. Uses getaddrinfo(3)
* if available, falling back to the traditional BSD mechanisms otherwise.
* Returns the connected socket or -1 on error.
*/
static int
_netopen(host, serv, typ)
char *host, *serv;
int typ;
{
#ifdef HAVE_GETADDRINFO
return (_netopen6 (host, serv, typ));
#else
return (_netopen4 (host, serv, typ));
#endif
}
/*
* Open a TCP or UDP connection given a path like `/dev/tcp/host/port' to
* host `host' on port `port' and return the connected socket.
*/
int
netopen (path)
char *path;
{
char *np, *s, *t;
int fd;
np = (char *)xmalloc (strlen (path) + 1);
strcpy (np, path);
s = np + 9;
t = strchr (s, '/');
if (t == 0)
{
internal_error (_("%s: bad network path specification"), path);
return -1;
}
*t++ = '\0';
fd = _netopen (s, t, path[5]);
free (np);
return fd;
}
#if 0
/*
* Open a TCP connection to host `host' on the port defined for service
* `serv' and return the connected socket.
*/
int
tcpopen (host, serv)
char *host, *serv;
{
return (_netopen (host, serv, 't'));
}
/*
* Open a UDP connection to host `host' on the port defined for service
* `serv' and return the connected socket.
*/
int
udpopen (host, serv)
char *host, *serv;
{
return _netopen (host, serv, 'u');
}
#endif
#else /* !HAVE_NETWORK */
int
netopen (path)
char *path;
{
internal_error (_("network operations not supported"));
return -1;
}
#endif /* !HAVE_NETWORK */
+1 -2
View File
@@ -57,8 +57,7 @@ sh_regmatch (string, pattern, flags)
char *subexp_str;
int subexp_len;
#endif
int result;
int result;
#if defined (ARRAY_VARS)
rematch = (SHELL_VAR *)NULL;
+121
View File
@@ -0,0 +1,121 @@
/* Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
/*
* shmatch.c -- shell interface to posix regular expression matching.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#if defined (HAVE_POSIX_REGEXP)
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "bashansi.h"
#include <stdio.h>
#include <regex.h>
#include "shell.h"
#include "variables.h"
#include "externs.h"
extern int glob_ignore_case, match_ignore_case;
int
sh_regmatch (string, pattern, flags)
const char *string;
const char *pattern;
int flags;
{
regex_t regex = { 0 };
regmatch_t *matches;
int rflags;
#if defined (ARRAY_VARS)
SHELL_VAR *rematch;
ARRAY *amatch;
int subexp_ind;
char *subexp_str;
int subexp_len;
#endif
int result;
#if defined (ARRAY_VARS)
rematch = (SHELL_VAR *)NULL;
#endif
rflags = REG_EXTENDED;
if (glob_ignore_case || match_ignore_case)
rflags |= REG_ICASE;
#if !defined (ARRAY_VARS)
rflags |= REG_NOSUB;
#endif
if (regcomp (&regex, pattern, rflags))
return 2; /* flag for printing a warning here. */
#if defined (ARRAY_VARS)
matches = (regmatch_t *)malloc (sizeof (regmatch_t) * (regex.re_nsub + 1));
#else
matches = NULL;
#endif
if (regexec (&regex, string, regex.re_nsub + 1, matches, 0))
result = EXECUTION_FAILURE;
else
result = EXECUTION_SUCCESS; /* match */
#if defined (ARRAY_VARS)
subexp_len = strlen (string) + 10;
subexp_str = malloc (subexp_len + 1);
/* Store the parenthesized subexpressions in the array BASH_REMATCH.
Element 0 is the portion that matched the entire regexp. Element 1
is the part that matched the first subexpression, and so on. */
unbind_variable ("BASH_REMATCH");
rematch = make_new_array_variable ("BASH_REMATCH");
amatch = array_cell (rematch);
if ((flags & SHMAT_SUBEXP) && result == EXECUTION_SUCCESS && subexp_str)
{
for (subexp_ind = 0; subexp_ind <= regex.re_nsub; subexp_ind++)
{
memset (subexp_str, 0, subexp_len);
strncpy (subexp_str, string + matches[subexp_ind].rm_so,
matches[subexp_ind].rm_eo - matches[subexp_ind].rm_so);
array_insert (amatch, subexp_ind, subexp_str);
}
}
VSETATTR (rematch, att_readonly);
free (subexp_str);
free (matches);
#endif /* ARRAY_VARS */
regfree (&regex);
return result;
}
#endif /* HAVE_POSIX_REGEXP */
+1 -1
View File
@@ -176,7 +176,7 @@ ansic_quote (str, flags, rlen)
int flags, *rlen;
{
char *r, *ret, *s;
int l, rsize, t;
int l, rsize;
unsigned char c;
if (str == 0 || *str == 0)
+3 -2
View File
@@ -47,6 +47,9 @@ extern int errno;
extern pid_t dollar_dollar_pid;
static char *get_sys_tmpdir __P((void));
static char *get_tmpdir __P((int));
static char *sys_tmpdir = (char *)NULL;
static int ntmpfiles;
static int tmpnamelen = -1;
@@ -55,8 +58,6 @@ static unsigned long filenum = 1L;
static char *
get_sys_tmpdir ()
{
struct stat sb;
if (sys_tmpdir)
return sys_tmpdir;
+214
View File
@@ -0,0 +1,214 @@
/*
* tmpfile.c - functions to create and safely open temp files for the shell.
*/
/* Copyright (C) 2000 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Bash is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with Bash; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#include <config.h>
#include <bashtypes.h>
#include <posixstat.h>
#include <posixtime.h>
#include <filecntl.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <shell.h>
#ifndef errno
extern int errno;
#endif
#define BASEOPENFLAGS (O_CREAT | O_TRUNC | O_EXCL)
#define DEFAULT_TMPDIR "." /* bogus default, should be changed */
#define DEFAULT_NAMEROOT "shtmp"
extern pid_t dollar_dollar_pid;
static char *sys_tmpdir = (char *)NULL;
static int ntmpfiles;
static int tmpnamelen = -1;
static unsigned long filenum = 1L;
static char *
get_sys_tmpdir ()
{
if (sys_tmpdir)
return sys_tmpdir;
#ifdef P_tmpdir
sys_tmpdir = P_tmpdir;
if (file_iswdir (sys_tmpdir))
return sys_tmpdir;
#endif
sys_tmpdir = "/tmp";
if (file_iswdir (sys_tmpdir))
return sys_tmpdir;
sys_tmpdir = "/var/tmp";
if (file_iswdir (sys_tmpdir))
return sys_tmpdir;
sys_tmpdir = "/usr/tmp";
if (file_iswdir (sys_tmpdir))
return sys_tmpdir;
sys_tmpdir = DEFAULT_TMPDIR;
return sys_tmpdir;
}
static char *
get_tmpdir (flags)
int flags;
{
char *tdir;
tdir = (flags & MT_USETMPDIR) ? get_string_value ("TMPDIR") : (char *)NULL;
if (tdir == 0)
tdir = get_sys_tmpdir ();
#if defined (HAVE_PATHCONF) && defined (_PC_NAME_MAX)
if (tmpnamelen == -1)
tmpnamelen = pathconf (tdir, _PC_NAME_MAX);
#else
tmpnamelen = 0;
#endif
return tdir;
}
char *
sh_mktmpname (nameroot, flags)
char *nameroot;
int flags;
{
char *filename, *tdir, *lroot;
struct stat sb;
int r, tdlen;
filename = (char *)xmalloc (PATH_MAX + 1);
tdir = get_tmpdir (flags);
tdlen = strlen (tdir);
lroot = nameroot ? nameroot : DEFAULT_NAMEROOT;
#ifdef USE_MKTEMP
sprintf (filename, "%s/%s.XXXXXX", tdir, lroot);
if (mktemp (filename) == 0)
{
free (filename);
filename = NULL;
}
#else /* !USE_MKTEMP */
while (1)
{
filenum = (filenum << 1) ^
(unsigned long) time ((time_t *)0) ^
(unsigned long) dollar_dollar_pid ^
(unsigned long) ((flags & MT_USERANDOM) ? get_random_number () : ntmpfiles++);
sprintf (filename, "%s/%s-%lu", tdir, lroot, filenum);
if (tmpnamelen > 0 && tmpnamelen < 32)
filename[tdlen + 1 + tmpnamelen] = '\0';
# ifdef HAVE_LSTAT
r = lstat (filename, &sb);
# else
r = stat (filename, &sb);
# endif
if (r < 0 && errno == ENOENT)
break;
}
#endif /* !USE_MKTEMP */
return filename;
}
int
sh_mktmpfd (nameroot, flags, namep)
char *nameroot;
int flags;
char **namep;
{
char *filename, *tdir, *lroot;
int fd, tdlen;
filename = (char *)xmalloc (PATH_MAX + 1);
tdir = get_tmpdir (flags);
tdlen = strlen (tdir);
lroot = nameroot ? nameroot : DEFAULT_NAMEROOT;
#ifdef USE_MKSTEMP
sprintf (filename, "%s/%s.XXXXXX", tdir, lroot);
fd = mkstemp (filename);
if (fd < 0 || namep == 0)
{
free (filename);
filename = NULL;
}
if (namep)
*namep = filename;
return fd;
#else /* !USE_MKSTEMP */
do
{
filenum = (filenum << 1) ^
(unsigned long) time ((time_t *)0) ^
(unsigned long) dollar_dollar_pid ^
(unsigned long) ((flags & MT_USERANDOM) ? get_random_number () : ntmpfiles++);
sprintf (filename, "%s/%s-%lu", tdir, lroot, filenum);
if (tmpnamelen > 0 && tmpnamelen < 32)
filename[tdlen + 1 + tmpnamelen] = '\0';
fd = open (filename, BASEOPENFLAGS | ((flags & MT_READWRITE) ? O_RDWR : O_WRONLY), 0600);
}
while (fd < 0 && errno == EEXIST);
if (namep)
*namep = filename;
else
free (filename);
return fd;
#endif /* !USE_MKSTEMP */
}
FILE *
sh_mktmpfp (nameroot, flags, namep)
char *nameroot;
int flags;
char **namep;
{
int fd;
FILE *fp;
fd = sh_mktmpfd (nameroot, flags, namep);
if (fd < 0)
return ((FILE *)NULL);
fp = fdopen (fd, (flags & MT_READWRITE) ? "w+" : "w");
if (fp == 0)
close (fd);
return fp;
}
+1
View File
@@ -55,6 +55,7 @@ extern int shell_tty;
#if defined (READLINE)
extern void rl_set_screen_size __P((int, int));
#endif
extern void sh_set_lines_and_columns __P((int, int));
void
get_new_window_size (from_sig, rp, cp)
+82
View File
@@ -0,0 +1,82 @@
/* Handle window size changes and information. */
/* Copyright (C) 2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#include "config.h"
#include <stdc.h>
#include "bashtypes.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <sys/ioctl.h>
#if !defined (STRUCT_WINSIZE_IN_SYS_IOCTL)
/* For struct winsize on SCO */
/* sys/ptem.h has winsize but needs mblk_t from sys/stream.h */
# if defined (HAVE_SYS_PTEM_H) && defined (TIOCGWINSZ) && defined (SIGWINCH)
# if defined (HAVE_SYS_STREAM_H)
# include <sys/stream.h>
# endif
# include <sys/ptem.h>
# endif /* HAVE_SYS_PTEM_H && TIOCGWINSZ && SIGWINCH */
#endif /* !STRUCT_WINSIZE_IN_SYS_IOCTL */
#include <stdio.h>
/* Return the fd from which we are actually getting input. */
#define input_tty() (shell_tty != -1) ? shell_tty : fileno (stderr)
#if !defined (errno)
extern int errno;
#endif /* !errno */
extern int shell_tty;
#if defined (READLINE)
extern void rl_set_screen_size __P((int, int));
#endif
void
get_new_window_size (from_sig, rp, cp)
int from_sig;
int *rp, *cp;
{
#if defined (TIOCGWINSZ)
struct winsize win;
int tty;
tty = input_tty ();
if (tty >= 0 && (ioctl (tty, TIOCGWINSZ, &win) == 0) &&
win.ws_row > 0 && win.ws_col > 0)
{
sh_set_lines_and_columns (win.ws_row, win.ws_col);
#if defined (READLINE)
rl_set_screen_size (win.ws_row, win.ws_col);
if (rp)
*rp = win.ws_row;
if (cp)
*cp = win.ws_col;
#endif
}
#endif
}
-1
View File
@@ -78,7 +78,6 @@ void
set_default_locale_vars ()
{
char *val;
int r;
#if defined (HAVE_SETLOCALE)
-1
View File
@@ -750,7 +750,6 @@ make_function_def (name, command, lineno, lstart)
#if defined (ARRAY_VARS)
SHELL_VAR *bash_source_v;
ARRAY *bash_source_a;
char *t;
#endif
temp = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF));
+7 -12
View File
@@ -205,10 +205,6 @@ static void reset_readline_prompt __P((void));
#endif
static void print_prompt __P((void));
#if defined (HISTORY)
char *history_delimiting_chars __P((void));
#endif
#if defined (HANDLE_MULTIBYTE)
static void set_line_mbstate __P((void));
static char *shell_input_line_property = NULL;
@@ -1876,7 +1872,6 @@ shell_getc (remove_quoted_newline)
register int i;
int c;
unsigned char uc;
static int mustpop = 0;
QUIT;
@@ -2956,8 +2951,8 @@ static int
parse_dparen (c)
int c;
{
int cmdtyp, len, sline;
char *wval, *wv2;
int cmdtyp, sline;
char *wval;
WORD_DESC *wd;
#if defined (ARITH_FOR_COMMAND)
@@ -4160,7 +4155,7 @@ decode_prompt_string (string)
case 'W':
{
/* Use the value of PWD because it is much more efficient. */
char t_string[PATH_MAX], *t;
char t_string[PATH_MAX];
int tlen;
temp = get_string_value ("PWD");
@@ -4371,15 +4366,15 @@ yyerror (msg)
}
static char *
error_token_from_token (token)
int token;
error_token_from_token (tok)
int tok;
{
char *t;
if (t = find_token_in_alist (token, word_token_alist, 0))
if (t = find_token_in_alist (tok, word_token_alist, 0))
return t;
if (t = find_token_in_alist (token, other_token_alist, 0))
if (t = find_token_in_alist (tok, other_token_alist, 0))
return t;
t = (char *)NULL;
+8 -9
View File
@@ -1876,7 +1876,6 @@ shell_getc (remove_quoted_newline)
register int i;
int c;
unsigned char uc;
static int mustpop = 0;
QUIT;
@@ -2563,7 +2562,7 @@ read_token (command)
#endif /* ALIAS */
/* Read a single word from input. Start by skipping blanks. */
while ((character = shell_getc (1)) != EOF && whitespace (character))
while ((character = shell_getc (1)) != EOF && shellblank (character))
;
if (character == EOF)
@@ -2956,8 +2955,8 @@ static int
parse_dparen (c)
int c;
{
int cmdtyp, len, sline;
char *wval, *wv2;
int cmdtyp, sline;
char *wval;
WORD_DESC *wd;
#if defined (ARITH_FOR_COMMAND)
@@ -4160,7 +4159,7 @@ decode_prompt_string (string)
case 'W':
{
/* Use the value of PWD because it is much more efficient. */
char t_string[PATH_MAX], *t;
char t_string[PATH_MAX];
int tlen;
temp = get_string_value ("PWD");
@@ -4371,15 +4370,15 @@ yyerror (msg)
}
static char *
error_token_from_token (token)
int token;
error_token_from_token (tok)
int tok;
{
char *t;
if (t = find_token_in_alist (token, word_token_alist, 0))
if (t = find_token_in_alist (tok, word_token_alist, 0))
return t;
if (t = find_token_in_alist (token, other_token_alist, 0))
if (t = find_token_in_alist (tok, other_token_alist, 0))
return t;
t = (char *)NULL;
+1 -1
View File
@@ -815,7 +815,7 @@ gen_wordlist_matches (cs, text)
{
WORD_LIST *l, *l2;
STRINGLIST *sl;
int nw, tlen, qc;
int nw, tlen;
char *ntxt; /* dequoted TEXT to use in comparisons */
if (cs->words == 0 || cs->words[0] == '\0')
+10 -16
View File
@@ -1583,7 +1583,8 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp)
while (delims[i])
{
#if defined (HANDLE_MULTIBYTE)
mbstate_t state_bak = state;
mbstate_t state_bak;
state_bak = state;
mblength = MBRLEN (delims + i, slength, &state);
if (MB_INVALIDCH (mblength))
state = state_bak;
@@ -2035,7 +2036,7 @@ list_string (string, separators, quoted)
sindex++;
/* An IFS character that is not IFS white space, along with any
adjacent IFS white space, shall delimit a field. (SUSv3) */
while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex]))
while (string[sindex] && spctabnl (string[sindex]) && isifs (string[sindex]))
sindex++;
}
}
@@ -2223,7 +2224,7 @@ do_compound_assignment (name, value, flags)
int flags;
{
SHELL_VAR *v;
int off, mklocal;
int mklocal;
WORD_LIST *list;
mklocal = flags & ASS_MKLOCAL;
@@ -2254,7 +2255,7 @@ do_assignment_internal (word, expand)
int expand;
{
int offset, tlen, appendop, assign_list, aflags;
char *name, *value, *ovalue, *nvalue;
char *name, *value;
SHELL_VAR *entry;
#if defined (ARRAY_VARS)
char *t;
@@ -2286,11 +2287,7 @@ do_assignment_internal (word, expand)
tlen = STRLEN (temp);
#if defined (ARRAY_VARS)
# if 0
if (expand && temp[0] == LPAREN && temp[tlen-1] == RPAREN)
#else
if (expand && (word->flags & W_COMPASSIGN))
#endif
{
assign_list = ni = 1;
value = extract_array_assignment_list (temp, &ni);
@@ -3346,9 +3343,8 @@ remove_wpattern (wparam, wstrlen, wpattern, op)
wchar_t *wpattern;
int op;
{
wchar_t wc;
int n, n1;
wchar_t *ret;
wchar_t wc, *ret;
int n;
switch (op)
{
@@ -3802,7 +3798,9 @@ getpattern (value, quoted, expandpat)
{
char *pat, *tword;
WORD_LIST *l;
#if 0
int i;
#endif
/* There is a problem here: how to handle single or double quotes in the
pattern string when the whole expression is between double quotes?
@@ -5655,7 +5653,7 @@ pos_params_pat_subst (string, pat, rep, mflags)
{
WORD_LIST *save, *params;
WORD_DESC *w;
char *ret, *tt;
char *ret;
save = params = list_rest_of_args ();
if (save == 0)
@@ -7576,9 +7574,6 @@ word_list_split (list)
for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
{
tresult = word_split (t->word, ifs_value);
#if 0
result = (WORD_LIST *) list_append (result, tresult);
#else
if (result == 0)
result = e = tresult;
else
@@ -7587,7 +7582,6 @@ word_list_split (list)
while (e->next)
e = e->next;
}
#endif
}
return (result);
}
+12 -14
View File
@@ -949,8 +949,8 @@ string_extract_verbatim (string, slen, sindex, charlist)
len = mbstowcs (wcharlist, charlist, 0);
if (len == -1)
len = 0;
wcharlist = (wchar_t *)xmalloc ((sizeof (wchar_t) * len) + 1);
mbstowcs (wcharlist, charlist, len);
wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1));
mbstowcs (wcharlist, charlist, len + 1);
}
if (wcschr (wcharlist, wc))
@@ -1583,7 +1583,8 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp)
while (delims[i])
{
#if defined (HANDLE_MULTIBYTE)
mbstate_t state_bak = state;
mbstate_t state_bak;
state_bak = state;
mblength = MBRLEN (delims + i, slength, &state);
if (MB_INVALIDCH (mblength))
state = state_bak;
@@ -2035,7 +2036,7 @@ list_string (string, separators, quoted)
sindex++;
/* An IFS character that is not IFS white space, along with any
adjacent IFS white space, shall delimit a field. (SUSv3) */
while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex]))
while (string[sindex] && spctabnl (string[sindex]) && isifs (string[sindex]))
sindex++;
}
}
@@ -2223,7 +2224,7 @@ do_compound_assignment (name, value, flags)
int flags;
{
SHELL_VAR *v;
int off, mklocal;
int mklocal;
WORD_LIST *list;
mklocal = flags & ASS_MKLOCAL;
@@ -2254,7 +2255,7 @@ do_assignment_internal (word, expand)
int expand;
{
int offset, tlen, appendop, assign_list, aflags;
char *name, *value, *ovalue, *nvalue;
char *name, *value;
SHELL_VAR *entry;
#if defined (ARRAY_VARS)
char *t;
@@ -2286,11 +2287,7 @@ do_assignment_internal (word, expand)
tlen = STRLEN (temp);
#if defined (ARRAY_VARS)
# if 0
if (expand && temp[0] == LPAREN && temp[tlen-1] == RPAREN)
#else
if (expand && (word->flags & W_COMPASSIGN))
#endif
{
assign_list = ni = 1;
value = extract_array_assignment_list (temp, &ni);
@@ -3346,9 +3343,8 @@ remove_wpattern (wparam, wstrlen, wpattern, op)
wchar_t *wpattern;
int op;
{
wchar_t wc;
int n, n1;
wchar_t *ret;
wchar_t wc, *ret;
int n;
switch (op)
{
@@ -3802,7 +3798,9 @@ getpattern (value, quoted, expandpat)
{
char *pat, *tword;
WORD_LIST *l;
#if 0
int i;
#endif
/* There is a problem here: how to handle single or double quotes in the
pattern string when the whole expression is between double quotes?
@@ -5655,7 +5653,7 @@ pos_params_pat_subst (string, pat, rep, mflags)
{
WORD_LIST *save, *params;
WORD_DESC *w;
char *ret, *tt;
char *ret;
save = params = list_rest_of_args ();
if (save == 0)
-1
View File
@@ -76,7 +76,6 @@ static void restore_signal __P((int));
static void reset_or_restore_signal_handlers __P((sh_resetsig_func_t *));
/* Variables used here but defined in other files. */
extern int interrupt_immediately;
extern int last_command_exit_value;
extern int line_number;
+6 -11
View File
@@ -888,18 +888,13 @@ reset_or_restore_signal_handlers (reset)
`functrace' or `errtrace' options have been set, then let command
substitutions inherit them. Let command substitution inherit the
RETURN trap if we're in the debugger and tracing functions. */
#if defined (DEBUGGER)
if (debugging_mode == 0 && function_trace_mode == 0)
#endif
sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED;
#if defined (DEBUGGER)
if (debugging_mode == 0 && error_trace_mode == 0)
#endif
if (function_trace_mode == 0)
{
sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED;
sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED;
}
if (error_trace_mode == 0)
sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED;
#if defined (DEBUGGER)
if (debugging_mode == 0 && function_trace_mode == 0)
#endif
sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED;
}
/* Reset trapped signals to their original values, but don't free the
-2
View File
@@ -73,8 +73,6 @@ typedef union uwp {
} UNWIND_ELT;
extern int interrupt_immediately;
static void without_interrupts __P((VFunction *, char *, char *));
static void unwind_frame_discard_internal __P((char *, char *));
static void unwind_frame_run_internal __P((char *, char *));
+320
View File
@@ -0,0 +1,320 @@
/* I can't stand it anymore! Please can't we just write the
whole Unix system in lisp or something? */
/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
/* **************************************************************** */
/* */
/* Unwind Protection Scheme for Bash */
/* */
/* **************************************************************** */
#include "config.h"
#include "bashtypes.h"
#include "bashansi.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if STDC_HEADERS
# include <stddef.h>
#endif
#ifndef offsetof
# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#include "command.h"
#include "general.h"
#include "unwind_prot.h"
#include "quit.h"
#include "sig.h"
/* Structure describing a saved variable and the value to restore it to. */
typedef struct {
char *variable;
int size;
char desired_setting[1]; /* actual size is `size' */
} SAVED_VAR;
/* If HEAD.CLEANUP is null, then ARG.V contains a tag to throw back to.
If HEAD.CLEANUP is restore_variable, then SV.V contains the saved
variable. Otherwise, call HEAD.CLEANUP (ARG.V) to clean up. */
typedef union uwp {
struct uwp_head {
union uwp *next;
Function *cleanup;
} head;
struct {
struct uwp_head uwp_head;
char *v;
} arg;
struct {
struct uwp_head uwp_head;
SAVED_VAR v;
} sv;
} UNWIND_ELT;
extern int interrupt_immediately;
static void without_interrupts __P((VFunction *, char *, char *));
static void unwind_frame_discard_internal __P((char *, char *));
static void unwind_frame_run_internal __P((char *, char *));
static void add_unwind_protect_internal __P((Function *, char *));
static void remove_unwind_protect_internal __P((char *, char *));
static void run_unwind_protects_internal __P((char *, char *));
static void clear_unwind_protects_internal __P((char *, char *));
static inline void restore_variable __P((SAVED_VAR *));
static void unwind_protect_mem_internal __P((char *, char *));
static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
#define uwpalloc(elt) (elt) = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT))
#define uwpfree(elt) free(elt)
/* Run a function without interrupts. This relies on the fact that the
FUNCTION cannot change the value of interrupt_immediately. (I.e., does
not call QUIT (). */
static void
without_interrupts (function, arg1, arg2)
VFunction *function;
char *arg1, *arg2;
{
int old_interrupt_immediately;
old_interrupt_immediately = interrupt_immediately;
interrupt_immediately = 0;
(*function)(arg1, arg2);
interrupt_immediately = old_interrupt_immediately;
}
/* Start the beginning of a region. */
void
begin_unwind_frame (tag)
char *tag;
{
add_unwind_protect ((Function *)NULL, tag);
}
/* Discard the unwind protects back to TAG. */
void
discard_unwind_frame (tag)
char *tag;
{
if (unwind_protect_list)
without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
}
/* Run the unwind protects back to TAG. */
void
run_unwind_frame (tag)
char *tag;
{
if (unwind_protect_list)
without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
}
/* Add the function CLEANUP with ARG to the list of unwindable things. */
void
add_unwind_protect (cleanup, arg)
Function *cleanup;
char *arg;
{
without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
}
/* Remove the top unwind protect from the list. */
void
remove_unwind_protect ()
{
if (unwind_protect_list)
without_interrupts
(remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
}
/* Run the list of cleanup functions in unwind_protect_list. */
void
run_unwind_protects ()
{
if (unwind_protect_list)
without_interrupts
(run_unwind_protects_internal, (char *)NULL, (char *)NULL);
}
/* Erase the unwind-protect list. If flags is 1, free the elements. */
void
clear_unwind_protect_list (flags)
int flags;
{
char *flag;
if (unwind_protect_list)
{
flag = flags ? "" : (char *)NULL;
without_interrupts
(clear_unwind_protects_internal, flag, (char *)NULL);
}
}
/* **************************************************************** */
/* */
/* The Actual Functions */
/* */
/* **************************************************************** */
static void
add_unwind_protect_internal (cleanup, arg)
Function *cleanup;
char *arg;
{
UNWIND_ELT *elt;
uwpalloc (elt);
elt->head.next = unwind_protect_list;
elt->head.cleanup = cleanup;
elt->arg.v = arg;
unwind_protect_list = elt;
}
static void
remove_unwind_protect_internal (ignore1, ignore2)
char *ignore1, *ignore2;
{
UNWIND_ELT *elt;
elt = unwind_protect_list;
if (elt)
{
unwind_protect_list = unwind_protect_list->head.next;
uwpfree (elt);
}
}
static void
run_unwind_protects_internal (ignore1, ignore2)
char *ignore1, *ignore2;
{
unwind_frame_run_internal ((char *) NULL, (char *) NULL);
}
static void
clear_unwind_protects_internal (flag, ignore)
char *flag, *ignore;
{
if (flag)
{
while (unwind_protect_list)
remove_unwind_protect_internal ((char *)NULL, (char *)NULL);
}
unwind_protect_list = (UNWIND_ELT *)NULL;
}
static void
unwind_frame_discard_internal (tag, ignore)
char *tag, *ignore;
{
UNWIND_ELT *elt;
while (elt = unwind_protect_list)
{
unwind_protect_list = unwind_protect_list->head.next;
if (elt->head.cleanup == 0 && (STREQ (elt->arg.v, tag)))
{
uwpfree (elt);
break;
}
else
uwpfree (elt);
}
}
/* Restore the value of a variable, based on the contents of SV.
sv->desired_setting is a block of memory SIZE bytes long holding the
value itself. This block of memory is copied back into the variable. */
static inline void
restore_variable (sv)
SAVED_VAR *sv;
{
FASTCOPY (sv->desired_setting, sv->variable, sv->size);
}
static void
unwind_frame_run_internal (tag, ignore)
char *tag, *ignore;
{
UNWIND_ELT *elt;
while (elt = unwind_protect_list)
{
unwind_protect_list = elt->head.next;
/* If tag, then compare. */
if (!elt->head.cleanup)
{
if (tag && STREQ (elt->arg.v, tag))
{
uwpfree (elt);
break;
}
}
else
{
if (elt->head.cleanup == (Function *) restore_variable)
restore_variable (&elt->sv.v);
else
(*(elt->head.cleanup)) (elt->arg.v);
}
uwpfree (elt);
}
}
static void
unwind_protect_mem_internal (var, psize)
char *var;
char *psize;
{
int size, allocated;
UNWIND_ELT *elt;
size = *(int *) psize;
allocated = size + offsetof (UNWIND_ELT, sv.v.desired_setting[0]);
elt = (UNWIND_ELT *)xmalloc (allocated);
elt->head.next = unwind_protect_list;
elt->head.cleanup = (Function *) restore_variable;
elt->sv.v.variable = var;
elt->sv.v.size = size;
FASTCOPY (var, elt->sv.v.desired_setting, size);
unwind_protect_list = elt;
}
/* Save the value of a variable so it will be restored when unwind-protects
are run. VAR is a pointer to the variable. SIZE is the size in
bytes of VAR. */
void
unwind_protect_mem (var, size)
char *var;
int size;
{
without_interrupts (unwind_protect_mem_internal, var, (char *) &size);
}
-14
View File
@@ -1306,20 +1306,11 @@ static SHELL_VAR *
get_comp_wordbreaks (var)
SHELL_VAR *var;
{
char *p;
/* If we don't have anything yet, assign a default value. */
if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0)
enable_hostname_completion (perform_hostname_completion);
#if 0
FREE (value_cell (var));
p = savestring (rl_completer_word_break_characters);
var_setvalue (var, p);
#else
var_setvalue (var, rl_completer_word_break_characters);
#endif
return (var);
}
@@ -2033,16 +2024,11 @@ bind_int_variable (lhs, rhs)
char *lhs, *rhs;
{
register SHELL_VAR *v;
char *t;
int isint, isarr;
isint = isarr = 0;
#if defined (ARRAY_VARS)
# if 0
if (t = xstrchr (lhs, '[')) /*]*/
# else
if (valid_array_reference (lhs))
# endif
{
isarr = 1;
v = array_variable_part (lhs, (char **)0, (int *)0);
-1
View File
@@ -330,7 +330,6 @@ extern int get_random_number __P((void));
extern void sv_ifs __P((char *));
extern void sv_path __P((char *));
extern void sv_mail __P((char *));
extern void sv_comp_wordbreaks __P((char *));
extern void sv_globignore __P((char *));
extern void sv_ignoreeof __P((char *));
extern void sv_strict_posix __P((char *));