mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-07-10 21:50:49 +02:00
commit bash-20100325 snapshot
This commit is contained in:
+95
-1
@@ -9524,7 +9524,7 @@ subst.c
|
||||
- in parameter_brace_expand, before calling parameter_brace_expand_rhs,
|
||||
add Q_DOLBRACE to `quoted' if we're within double quotes.
|
||||
- in expand_word_internal, if the Q_DOLBRACE flag is set, remove a
|
||||
backslash escaping a { or }. Result of a Posix discussion on the
|
||||
backslash escaping a }. Result of a Posix discussion on the
|
||||
austin-group list
|
||||
|
||||
2/27
|
||||
@@ -9595,3 +9595,97 @@ lib/sh/xmbsrtowcs.c
|
||||
mbsnrtowcs is available and the indices are not required. Called
|
||||
from xdupmbstowcs as required. Initial patch from
|
||||
<0xe2.0x9a.0x9b@gmail.com>
|
||||
|
||||
3/22
|
||||
----
|
||||
print_cmd.c
|
||||
- call print_deferred_heredocs virtually every time a recursive call
|
||||
to make_command_string_internal is made so here documents get
|
||||
printed correctly when they are attached to commands inside compound
|
||||
commands such as for and while. Fixes bug reported by Mike
|
||||
Frysinger <vapier@gentoo.org>
|
||||
|
||||
3/25
|
||||
----
|
||||
builtins/printf.def
|
||||
- fix have_precision case in PF macro to call printf with precision
|
||||
instead of fieldwidth argument. Fixes bug reported by Rob Robason
|
||||
<rob@robason.net>
|
||||
|
||||
3/26
|
||||
----
|
||||
trap.[ch]
|
||||
- new function, signal_is_hard_ignored, returns true if the shell
|
||||
inherited SIG_IGN as a signal's disposition
|
||||
- new function, set_original_signal (sig, handler), provides interface
|
||||
for rest of shell to set original_signals[sig] = handler
|
||||
|
||||
execute_cmd.c
|
||||
- execute_disk_command needs to call reset_terminating_signals in the
|
||||
child process before resetting traps with restore_original_signals
|
||||
|
||||
builtins/trap.def
|
||||
- call initialize_terminating_signals before calling display_traps for
|
||||
trap -p or trap without any other arguments. Possible future use
|
||||
|
||||
lib/readline/complete.c
|
||||
- rl_filename_completion_function needs to call
|
||||
rl_filename_dequoting_function with `dirname' (which has already
|
||||
been tilde-expanded) instead of `users_dirname', because it calls
|
||||
opendir with `dirname'. Fixes bug reported by Stefan H. Holek
|
||||
<stefan@jarn.com>
|
||||
|
||||
3/27
|
||||
----
|
||||
sig.c
|
||||
- experimental change to set_signal_handler: when setting the SIGCHLD
|
||||
handler, set the SA_RESTART flag so that interruptible system calls
|
||||
get restarted after a child dies. Fixes bug reported by Tomas
|
||||
Trnka <tomastrnka@gmx.com>, but needs further evaluation
|
||||
|
||||
lib/sh/eaccess.c
|
||||
- eaccess(2) apparently does only half the job: it does not check that
|
||||
the permission bits on a file actually allow, for instance, execution.
|
||||
Need to augment with a call to sh_stataccess if eaccess returns
|
||||
success on FreeBSD. Fixes FreeBSD problem reported by Jonan Hattne
|
||||
<johan.hattne@utsouthwestern.edu>
|
||||
|
||||
3/28
|
||||
----
|
||||
parse.y,bashline.c,externs.h
|
||||
- history_delimiting_chars now takes a const char * as an argument:
|
||||
the line being added to the history. Changed callers
|
||||
|
||||
parse.y
|
||||
- bash_add_history should not add a semicolon separator if the current
|
||||
history entry already ends in a newline. It can introduce syntax
|
||||
errors (e.g., when it results in a null command before a close brace).
|
||||
Fixes bug reported by Andreas Schwab <schwab@linux-m68k.org>
|
||||
|
||||
parse.y
|
||||
- history_delimiting_chars needs to return a newline instead of a
|
||||
semicolon if it thinks the current line starts a here document
|
||||
(if it contains `<<'). Also keeps track of the fact with a new
|
||||
static variable, LAST_WAS_HEREDOC, so it can return the right
|
||||
sequence of newlines later for the here-document body. Fixes bug
|
||||
reported by Andreas Schwab <schwab@linux-m68k.org>
|
||||
|
||||
3/29
|
||||
----
|
||||
lib/sh/eaccess.c
|
||||
- if the system has faccessat, sh_eaccess will now use it in
|
||||
preference to all other options
|
||||
|
||||
3/30
|
||||
----
|
||||
subst.h
|
||||
- new string_extract and extract_dollar_brace_string flag value:
|
||||
SX_POSIXEXP, set if the shell is expanding one of the new Posix
|
||||
pattern removal word expansions
|
||||
|
||||
parser.h
|
||||
- new definitions for "word expansion state", shared between parse.y
|
||||
and subst.c
|
||||
|
||||
subst.c
|
||||
- include parser.h
|
||||
|
||||
+91
-3
@@ -9524,7 +9524,7 @@ subst.c
|
||||
- in parameter_brace_expand, before calling parameter_brace_expand_rhs,
|
||||
add Q_DOLBRACE to `quoted' if we're within double quotes.
|
||||
- in expand_word_internal, if the Q_DOLBRACE flag is set, remove a
|
||||
backslash escaping a { or }. Result of a Posix discussion on the
|
||||
backslash escaping a }. Result of a Posix discussion on the
|
||||
austin-group list
|
||||
|
||||
2/27
|
||||
@@ -9592,5 +9592,93 @@ configure.in,config.h.in
|
||||
|
||||
lib/sh/xmbsrtowcs.c
|
||||
- new function, xdupmbstowcs2, fast version of xdupmbstowcs used when
|
||||
mbsnrtowcs is available and the indices are not required. Initial
|
||||
patch from <0xe2.0x9a.0x9b@gmail.com>
|
||||
mbsnrtowcs is available and the indices are not required. Called
|
||||
from xdupmbstowcs as required. Initial patch from
|
||||
<0xe2.0x9a.0x9b@gmail.com>
|
||||
|
||||
3/22
|
||||
----
|
||||
print_cmd.c
|
||||
- call print_deferred_heredocs virtually every time a recursive call
|
||||
to make_command_string_internal is made so here documents get
|
||||
printed correctly when they are attached to commands inside compound
|
||||
commands such as for and while. Fixes bug reported by Mike
|
||||
Frysinger <vapier@gentoo.org>
|
||||
|
||||
3/25
|
||||
----
|
||||
builtins/printf.def
|
||||
- fix have_precision case in PF macro to call printf with precision
|
||||
instead of fieldwidth argument. Fixes bug reported by Rob Robason
|
||||
<rob@robason.net>
|
||||
|
||||
3/26
|
||||
----
|
||||
trap.[ch]
|
||||
- new function, signal_is_hard_ignored, returns true if the shell
|
||||
inherited SIG_IGN as a signal's disposition
|
||||
- new function, set_original_signal (sig, handler), provides interface
|
||||
for rest of shell to set original_signals[sig] = handler
|
||||
|
||||
execute_cmd.c
|
||||
- execute_disk_command needs to call reset_terminating_signals in the
|
||||
child process before resetting traps with restore_original_signals
|
||||
|
||||
builtins/trap.def
|
||||
- call initialize_terminating_signals before calling display_traps for
|
||||
trap -p or trap without any other arguments. Possible future use
|
||||
|
||||
lib/readline/complete.c
|
||||
- rl_filename_completion_function needs to call
|
||||
rl_filename_dequoting_function with `dirname' (which has already
|
||||
been tilde-expanded) instead of `users_dirname', because it calls
|
||||
opendir with `dirname'. Fixes bug reported by Stefan H. Holek
|
||||
<stefan@jarn.com>
|
||||
|
||||
3/27
|
||||
----
|
||||
sig.c
|
||||
- experimental change to set_signal_handler: when setting the SIGCHLD
|
||||
handler, set the SA_RESTART flag so that interruptible system calls
|
||||
get restarted after a child dies. Fixes bug reported by Tomas
|
||||
Trnka <tomastrnka@gmx.com>, but needs further evaluation
|
||||
|
||||
lib/sh/eaccess.c
|
||||
- eaccess(2) apparently does only half the job: it does not check that
|
||||
the permission bits on a file actually allow, for instance, execution.
|
||||
Need to augment with a call to sh_stataccess if eaccess returns
|
||||
success on FreeBSD. Fixes FreeBSD problem reported by Jonan Hattne
|
||||
<johan.hattne@utsouthwestern.edu>
|
||||
|
||||
3/28
|
||||
----
|
||||
parse.y,bashline.c,externs.h
|
||||
- history_delimiting_chars now takes a const char * as an argument:
|
||||
the line being added to the history. Changed callers
|
||||
|
||||
parse.y
|
||||
- bash_add_history should not add a semicolon separator if the current
|
||||
history entry already ends in a newline. It can introduce syntax
|
||||
errors (e.g., when it results in a null command before a close brace).
|
||||
Fixes bug reported by Andreas Schwab <schwab@linux-m68k.org>
|
||||
|
||||
parse.y
|
||||
- history_delimiting_chars needs to return a newline instead of a
|
||||
semicolon if it thinks the current line starts a here document
|
||||
(if it contains `<<'). Also keeps track of the fact with a new
|
||||
static variable, LAST_WAS_HEREDOC, so it can return the right
|
||||
sequence of newlines later for the here-document body. Fixes bug
|
||||
reported by Andreas Schwab <schwab@linux-m68k.org>
|
||||
|
||||
3/29
|
||||
----
|
||||
lib/sh/eaccess.c
|
||||
- if the system has faccessat, sh_eaccess will now use it in
|
||||
preference to all other options
|
||||
|
||||
3/30
|
||||
----
|
||||
subst.h
|
||||
- new string_extract and extract_dollar_brace_string flag value:
|
||||
SX_POSIXEXP, set if the shell is expanding one of the new Posix
|
||||
pattern removal word expansions
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern char *sys_siglist[];
|
||||
extern const char * const sys_siglist[];
|
||||
|
||||
typedef void sighandler();
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/* sigs - print signal dispositions for a process */
|
||||
|
||||
/* Copyright (C) 1990-2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern char *sys_siglist[];
|
||||
|
||||
typedef void sighandler();
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
register int i;
|
||||
sighandler *h;
|
||||
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
h = signal(i, SIG_DFL);
|
||||
if (h != SIG_DFL) {
|
||||
if (h == SIG_IGN)
|
||||
fprintf(stderr, "%d: ignored (%s)\n", i, sys_siglist[i]);
|
||||
else
|
||||
fprintf(stderr, "%d: caught (%s)\n", i, sys_siglist[i]);
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -969,7 +969,7 @@ mailcheck.o: execute_cmd.h mailcheck.h
|
||||
make_cmd.o: config.h bashtypes.h ${BASHINCDIR}/filecntl.h bashansi.h
|
||||
make_cmd.o: command.h ${BASHINCDIR}/stdc.h general.h xmalloc.h error.h flags.h make_cmd.h
|
||||
make_cmd.o: variables.h arrayfunc.h conftypes.h array.h hashlib.h subst.h input.h externs.h
|
||||
make_cmd.o: jobs.h quit.h siglist.h syntax.h dispose_cmd.h
|
||||
make_cmd.o: jobs.h quit.h siglist.h syntax.h dispose_cmd.h parser.h
|
||||
make_cmd.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/ocache.h
|
||||
y.tab.o: config.h bashtypes.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/memalloc.h
|
||||
y.tab.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h
|
||||
@@ -1022,7 +1022,7 @@ subst.o: config.h bashtypes.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDI
|
||||
subst.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h
|
||||
subst.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h
|
||||
subst.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h
|
||||
subst.o: make_cmd.h subst.h sig.h pathnames.h externs.h
|
||||
subst.o: make_cmd.h subst.h sig.h pathnames.h externs.h parser.h
|
||||
subst.o: flags.h jobs.h siglist.h execute_cmd.h ${BASHINCDIR}/filecntl.h trap.h pathexp.h
|
||||
subst.o: mailcheck.h input.h $(DEFSRC)/getopt.h $(DEFSRC)/common.h
|
||||
subst.o: bashline.h bashhist.h ${GLOB_LIBSRC}/strmatch.h
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
# Makefile for bash-4.0, version 3.5
|
||||
# Makefile for bash-4.1, version 4.1
|
||||
#
|
||||
# Copyright (C) 1996-2009 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1996-2010 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -969,7 +969,7 @@ mailcheck.o: execute_cmd.h mailcheck.h
|
||||
make_cmd.o: config.h bashtypes.h ${BASHINCDIR}/filecntl.h bashansi.h
|
||||
make_cmd.o: command.h ${BASHINCDIR}/stdc.h general.h xmalloc.h error.h flags.h make_cmd.h
|
||||
make_cmd.o: variables.h arrayfunc.h conftypes.h array.h hashlib.h subst.h input.h externs.h
|
||||
make_cmd.o: jobs.h quit.h siglist.h syntax.h dispose_cmd.h
|
||||
make_cmd.o: jobs.h quit.h siglist.h syntax.h dispose_cmd.h parser.h
|
||||
make_cmd.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/ocache.h
|
||||
y.tab.o: config.h bashtypes.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/memalloc.h
|
||||
y.tab.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@%:@! /bin/sh
|
||||
@%:@ From configure.in for Bash 4.1, version 4.022.
|
||||
@%:@ From configure.in for Bash 4.1, version 4.023.
|
||||
@%:@ Guess values for system-dependent variables and create Makefiles.
|
||||
@%:@ Generated by GNU Autoconf 2.63 for bash 4.1-maint.
|
||||
@%:@
|
||||
@@ -13577,7 +13577,8 @@ done
|
||||
|
||||
|
||||
|
||||
for ac_func in bcopy bzero confstr fnmatch \
|
||||
|
||||
for ac_func in bcopy bzero confstr faccessat fnmatch \
|
||||
getaddrinfo gethostbyname getservbyname getservent inet_aton \
|
||||
memmove pathconf putenv raise regcomp regexec \
|
||||
setenv setlinebuf setlocale setvbuf siginterrupt strchr \
|
||||
|
||||
+11
-11
@@ -15,25 +15,25 @@
|
||||
'configure.in'
|
||||
],
|
||||
{
|
||||
'AM_PROG_F77_C_O' => 1,
|
||||
'_LT_AC_TAGCONFIG' => 1,
|
||||
'm4_pattern_forbid' => 1,
|
||||
'AM_PROG_F77_C_O' => 1,
|
||||
'AC_INIT' => 1,
|
||||
'AC_CANONICAL_TARGET' => 1,
|
||||
'm4_pattern_forbid' => 1,
|
||||
'_AM_COND_IF' => 1,
|
||||
'AC_CONFIG_LIBOBJ_DIR' => 1,
|
||||
'AC_CANONICAL_TARGET' => 1,
|
||||
'AC_SUBST' => 1,
|
||||
'AC_CANONICAL_HOST' => 1,
|
||||
'AC_CONFIG_LIBOBJ_DIR' => 1,
|
||||
'AC_FC_SRCEXT' => 1,
|
||||
'AC_CANONICAL_HOST' => 1,
|
||||
'AC_PROG_LIBTOOL' => 1,
|
||||
'AM_INIT_AUTOMAKE' => 1,
|
||||
'AC_CONFIG_SUBDIRS' => 1,
|
||||
'AM_AUTOMAKE_VERSION' => 1,
|
||||
'LT_CONFIG_LTDL_DIR' => 1,
|
||||
'AC_CONFIG_LINKS' => 1,
|
||||
'AC_REQUIRE_AUX_FILE' => 1,
|
||||
'LT_SUPPORTED_TAG' => 1,
|
||||
'AC_CONFIG_LINKS' => 1,
|
||||
'm4_sinclude' => 1,
|
||||
'LT_SUPPORTED_TAG' => 1,
|
||||
'AM_MAINTAINER_MODE' => 1,
|
||||
'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
|
||||
'_m4_warn' => 1,
|
||||
@@ -49,13 +49,13 @@
|
||||
'AC_CANONICAL_BUILD' => 1,
|
||||
'AC_FC_FREEFORM' => 1,
|
||||
'AH_OUTPUT' => 1,
|
||||
'AC_CONFIG_AUX_DIR' => 1,
|
||||
'_AM_SUBST_NOTMAKE' => 1,
|
||||
'AM_PROG_CC_C_O' => 1,
|
||||
'm4_pattern_allow' => 1,
|
||||
'AC_CONFIG_AUX_DIR' => 1,
|
||||
'sinclude' => 1,
|
||||
'AM_CONDITIONAL' => 1,
|
||||
'm4_pattern_allow' => 1,
|
||||
'AM_PROG_CC_C_O' => 1,
|
||||
'AC_CANONICAL_SYSTEM' => 1,
|
||||
'AM_CONDITIONAL' => 1,
|
||||
'AC_CONFIG_HEADERS' => 1,
|
||||
'AC_DEFINE_TRACE_LITERAL' => 1,
|
||||
'm4_include' => 1,
|
||||
|
||||
@@ -1352,6 +1352,8 @@ m4trace:configure.in:730: -1- AH_OUTPUT([HAVE_BZERO], [/* Define to 1 if you hav
|
||||
#undef HAVE_BZERO])
|
||||
m4trace:configure.in:730: -1- AH_OUTPUT([HAVE_CONFSTR], [/* Define to 1 if you have the `confstr\' function. */
|
||||
#undef HAVE_CONFSTR])
|
||||
m4trace:configure.in:730: -1- AH_OUTPUT([HAVE_FACCESSAT], [/* Define to 1 if you have the `faccessat\' function. */
|
||||
#undef HAVE_FACCESSAT])
|
||||
m4trace:configure.in:730: -1- AH_OUTPUT([HAVE_FNMATCH], [/* Define to 1 if you have the `fnmatch\' function. */
|
||||
#undef HAVE_FNMATCH])
|
||||
m4trace:configure.in:730: -1- AH_OUTPUT([HAVE_GETADDRINFO], [/* Define to 1 if you have the `getaddrinfo\' function. */
|
||||
|
||||
+8
-3
@@ -184,6 +184,7 @@ int dont_save_function_defs;
|
||||
extern int current_command_line_count;
|
||||
|
||||
extern struct dstack dstack;
|
||||
extern int parser_state;
|
||||
|
||||
static int bash_history_inhibit_expansion __P((char *, int));
|
||||
#if defined (READLINE)
|
||||
@@ -731,7 +732,7 @@ bash_add_history (line)
|
||||
add_it = 1;
|
||||
if (command_oriented_history && current_command_line_count > 1)
|
||||
{
|
||||
chars_to_add = literal_history ? "\n" : history_delimiting_chars ();
|
||||
chars_to_add = literal_history ? "\n" : history_delimiting_chars (line);
|
||||
|
||||
using_history ();
|
||||
current = previous_history ();
|
||||
@@ -751,8 +752,12 @@ bash_add_history (line)
|
||||
chars_to_add = "";
|
||||
}
|
||||
|
||||
if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\n' && *chars_to_add == ';')
|
||||
chars_to_add++;
|
||||
/* If we're not in some kind of quoted construct, the current history
|
||||
entry ends with a newline, and we're going to add a semicolon,
|
||||
don't. In some cases, it results in a syntax error (e.g., before
|
||||
a close brace), and it should not be needed. */
|
||||
if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\n' && *chars_to_add == ';')
|
||||
chars_to_add++;
|
||||
|
||||
new_line = (char *)xmalloc (1
|
||||
+ curlen
|
||||
|
||||
+898
@@ -0,0 +1,898 @@
|
||||
/* bashhist.c -- bash interface to the GNU history library. */
|
||||
|
||||
/* Copyright (C) 1993-2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HISTORY)
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "bashansi.h"
|
||||
#include "posixstat.h"
|
||||
#include "filecntl.h"
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#if defined (SYSLOG_HISTORY)
|
||||
# include <syslog.h>
|
||||
#endif
|
||||
|
||||
#include "shell.h"
|
||||
#include "flags.h"
|
||||
#include "input.h"
|
||||
#include "parser.h" /* for the struct dstack stuff. */
|
||||
#include "pathexp.h" /* for the struct ignorevar stuff */
|
||||
#include "bashhist.h" /* matching prototypes and declarations */
|
||||
#include "builtins/common.h"
|
||||
|
||||
#include <readline/history.h>
|
||||
#include <glob/glob.h>
|
||||
#include <glob/strmatch.h>
|
||||
|
||||
#if defined (READLINE)
|
||||
# include "bashline.h"
|
||||
extern int rl_done, rl_dispatching; /* should really include readline.h */
|
||||
#endif
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
static int histignore_item_func __P((struct ign *));
|
||||
static int check_history_control __P((char *));
|
||||
static void hc_erasedups __P((char *));
|
||||
static void really_add_history __P((char *));
|
||||
|
||||
static struct ignorevar histignore =
|
||||
{
|
||||
"HISTIGNORE",
|
||||
(struct ign *)0,
|
||||
0,
|
||||
(char *)0,
|
||||
(sh_iv_item_func_t *)histignore_item_func,
|
||||
};
|
||||
|
||||
#define HIGN_EXPAND 0x01
|
||||
|
||||
/* Declarations of bash history variables. */
|
||||
/* Non-zero means to remember lines typed to the shell on the history
|
||||
list. This is different than the user-controlled behaviour; this
|
||||
becomes zero when we read lines from a file, for example. */
|
||||
int remember_on_history = 1;
|
||||
int enable_history_list = 1; /* value for `set -o history' */
|
||||
|
||||
/* The number of lines that Bash has added to this history session. The
|
||||
difference between the number of the top element in the history list
|
||||
(offset from history_base) and the number of lines in the history file.
|
||||
Appending this session's history to the history file resets this to 0. */
|
||||
int history_lines_this_session;
|
||||
|
||||
/* The number of lines that Bash has read from the history file. */
|
||||
int history_lines_in_file;
|
||||
|
||||
#if defined (BANG_HISTORY)
|
||||
/* Non-zero means do no history expansion on this line, regardless
|
||||
of what history_expansion says. */
|
||||
int history_expansion_inhibited;
|
||||
#endif
|
||||
|
||||
/* With the old default, every line was saved in the history individually.
|
||||
I.e., if the user enters:
|
||||
bash$ for i in a b c
|
||||
> do
|
||||
> echo $i
|
||||
> done
|
||||
Each line will be individually saved in the history.
|
||||
bash$ history
|
||||
10 for i in a b c
|
||||
11 do
|
||||
12 echo $i
|
||||
13 done
|
||||
14 history
|
||||
If the variable command_oriented_history is set, multiple lines
|
||||
which form one command will be saved as one history entry.
|
||||
bash$ for i in a b c
|
||||
> do
|
||||
> echo $i
|
||||
> done
|
||||
bash$ history
|
||||
10 for i in a b c
|
||||
do
|
||||
echo $i
|
||||
done
|
||||
11 history
|
||||
The user can then recall the whole command all at once instead
|
||||
of just being able to recall one line at a time.
|
||||
|
||||
This is now enabled by default.
|
||||
*/
|
||||
int command_oriented_history = 1;
|
||||
|
||||
/* Set to 1 if the first line of a possibly-multi-line command was saved
|
||||
in the history list. Managed by maybe_add_history(), but global so
|
||||
the history-manipluating builtins can see it. */
|
||||
int current_command_first_line_saved = 0;
|
||||
|
||||
/* Non-zero means to store newlines in the history list when using
|
||||
command_oriented_history rather than trying to use semicolons. */
|
||||
int literal_history;
|
||||
|
||||
/* Non-zero means to append the history to the history file at shell
|
||||
exit, even if the history has been stifled. */
|
||||
int force_append_history;
|
||||
|
||||
/* A nit for picking at history saving. Flags have the following values:
|
||||
|
||||
Value == 0 means save all lines parsed by the shell on the history.
|
||||
Value & HC_IGNSPACE means save all lines that do not start with a space.
|
||||
Value & HC_IGNDUPS means save all lines that do not match the last
|
||||
line saved.
|
||||
Value & HC_ERASEDUPS means to remove all other matching lines from the
|
||||
history list before saving the latest line. */
|
||||
int history_control;
|
||||
|
||||
/* Set to 1 if the last command was added to the history list successfully
|
||||
as a separate history entry; set to 0 if the line was ignored or added
|
||||
to a previous entry as part of command-oriented-history processing. */
|
||||
int hist_last_line_added;
|
||||
|
||||
/* Set to 1 if builtins/history.def:push_history added the last history
|
||||
entry. */
|
||||
int hist_last_line_pushed;
|
||||
|
||||
#if defined (READLINE)
|
||||
/* If non-zero, and readline is being used, the user is offered the
|
||||
chance to re-edit a failed history expansion. */
|
||||
int history_reediting;
|
||||
|
||||
/* If non-zero, and readline is being used, don't directly execute a
|
||||
line with history substitution. Reload it into the editing buffer
|
||||
instead and let the user further edit and confirm with a newline. */
|
||||
int hist_verify;
|
||||
|
||||
#endif /* READLINE */
|
||||
|
||||
/* Non-zero means to not save function definitions in the history list. */
|
||||
int dont_save_function_defs;
|
||||
|
||||
/* Variables declared in other files used here. */
|
||||
extern int current_command_line_count;
|
||||
|
||||
extern struct dstack dstack;
|
||||
|
||||
static int bash_history_inhibit_expansion __P((char *, int));
|
||||
#if defined (READLINE)
|
||||
static void re_edit __P((char *));
|
||||
#endif
|
||||
static int history_expansion_p __P((char *));
|
||||
static int shell_comment __P((char *));
|
||||
static int should_expand __P((char *));
|
||||
static HIST_ENTRY *last_history_entry __P((void));
|
||||
static char *expand_histignore_pattern __P((char *));
|
||||
static int history_should_ignore __P((char *));
|
||||
|
||||
/* Is the history expansion starting at string[i] one that should not
|
||||
be expanded? */
|
||||
static int
|
||||
bash_history_inhibit_expansion (string, i)
|
||||
char *string;
|
||||
int i;
|
||||
{
|
||||
/* The shell uses ! as a pattern negation character in globbing [...]
|
||||
expressions, so let those pass without expansion. */
|
||||
if (i > 0 && (string[i - 1] == '[') && member (']', string + i + 1))
|
||||
return (1);
|
||||
/* The shell uses ! as the indirect expansion character, so let those
|
||||
expansions pass as well. */
|
||||
else if (i > 1 && string[i - 1] == '{' && string[i - 2] == '$' &&
|
||||
member ('}', string + i + 1))
|
||||
return (1);
|
||||
#if defined (EXTENDED_GLOB)
|
||||
else if (extended_glob && i > 1 && string[i+1] == '(' && member (')', string + i + 2))
|
||||
return (1);
|
||||
#endif
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
bash_initialize_history ()
|
||||
{
|
||||
history_quotes_inhibit_expansion = 1;
|
||||
history_search_delimiter_chars = ";&()|<>";
|
||||
history_inhibit_expansion_function = bash_history_inhibit_expansion;
|
||||
#if defined (BANG_HISTORY)
|
||||
sv_histchars ("histchars");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
bash_history_reinit (interact)
|
||||
int interact;
|
||||
{
|
||||
#if defined (BANG_HISTORY)
|
||||
history_expansion = interact != 0;
|
||||
history_expansion_inhibited = 1;
|
||||
#endif
|
||||
remember_on_history = enable_history_list = interact != 0;
|
||||
history_inhibit_expansion_function = bash_history_inhibit_expansion;
|
||||
}
|
||||
|
||||
void
|
||||
bash_history_disable ()
|
||||
{
|
||||
remember_on_history = 0;
|
||||
#if defined (BANG_HISTORY)
|
||||
history_expansion_inhibited = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
bash_history_enable ()
|
||||
{
|
||||
remember_on_history = 1;
|
||||
#if defined (BANG_HISTORY)
|
||||
history_expansion_inhibited = 0;
|
||||
#endif
|
||||
history_inhibit_expansion_function = bash_history_inhibit_expansion;
|
||||
sv_history_control ("HISTCONTROL");
|
||||
sv_histignore ("HISTIGNORE");
|
||||
}
|
||||
|
||||
/* Load the history list from the history file. */
|
||||
void
|
||||
load_history ()
|
||||
{
|
||||
char *hf;
|
||||
|
||||
/* Truncate history file for interactive shells which desire it.
|
||||
Note that the history file is automatically truncated to the
|
||||
size of HISTSIZE if the user does not explicitly set the size
|
||||
differently. */
|
||||
set_if_not ("HISTSIZE", "500");
|
||||
sv_histsize ("HISTSIZE");
|
||||
|
||||
set_if_not ("HISTFILESIZE", get_string_value ("HISTSIZE"));
|
||||
sv_histsize ("HISTFILESIZE");
|
||||
|
||||
/* Read the history in HISTFILE into the history list. */
|
||||
hf = get_string_value ("HISTFILE");
|
||||
|
||||
if (hf && *hf && file_exists (hf))
|
||||
{
|
||||
read_history (hf);
|
||||
using_history ();
|
||||
history_lines_in_file = where_history ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bash_clear_history ()
|
||||
{
|
||||
clear_history ();
|
||||
history_lines_this_session = 0;
|
||||
}
|
||||
|
||||
/* Delete and free the history list entry at offset I. */
|
||||
int
|
||||
bash_delete_histent (i)
|
||||
int i;
|
||||
{
|
||||
HIST_ENTRY *discard;
|
||||
|
||||
discard = remove_history (i);
|
||||
if (discard)
|
||||
free_history_entry (discard);
|
||||
history_lines_this_session--;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
bash_delete_last_history ()
|
||||
{
|
||||
register int i;
|
||||
HIST_ENTRY **hlist, *histent;
|
||||
int r;
|
||||
|
||||
hlist = history_list ();
|
||||
if (hlist == NULL)
|
||||
return 0;
|
||||
|
||||
for (i = 0; hlist[i]; i++)
|
||||
;
|
||||
i--;
|
||||
|
||||
/* History_get () takes a parameter that must be offset by history_base. */
|
||||
histent = history_get (history_base + i); /* Don't free this */
|
||||
if (histent == NULL)
|
||||
return 0;
|
||||
|
||||
r = bash_delete_histent (i);
|
||||
|
||||
if (where_history () > history_length)
|
||||
history_set_pos (history_length);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* Write the existing history out to the history file. */
|
||||
void
|
||||
save_history ()
|
||||
{
|
||||
char *hf;
|
||||
|
||||
hf = get_string_value ("HISTFILE");
|
||||
if (hf && *hf && file_exists (hf))
|
||||
{
|
||||
/* Append only the lines that occurred this session to
|
||||
the history file. */
|
||||
using_history ();
|
||||
|
||||
if (history_lines_this_session < where_history () || force_append_history)
|
||||
append_history (history_lines_this_session, hf);
|
||||
else
|
||||
write_history (hf);
|
||||
sv_histsize ("HISTFILESIZE");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
maybe_append_history (filename)
|
||||
char *filename;
|
||||
{
|
||||
int fd, result;
|
||||
struct stat buf;
|
||||
|
||||
result = EXECUTION_SUCCESS;
|
||||
if (history_lines_this_session && (history_lines_this_session < where_history ()))
|
||||
{
|
||||
/* If the filename was supplied, then create it if necessary. */
|
||||
if (stat (filename, &buf) == -1 && errno == ENOENT)
|
||||
{
|
||||
fd = open (filename, O_WRONLY|O_CREAT, 0600);
|
||||
if (fd < 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot create: %s"), filename, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
close (fd);
|
||||
}
|
||||
result = append_history (history_lines_this_session, filename);
|
||||
history_lines_in_file += history_lines_this_session;
|
||||
history_lines_this_session = 0;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* If this is an interactive shell, then append the lines executed
|
||||
this session to the history file. */
|
||||
int
|
||||
maybe_save_shell_history ()
|
||||
{
|
||||
int result;
|
||||
char *hf;
|
||||
|
||||
result = 0;
|
||||
if (history_lines_this_session)
|
||||
{
|
||||
hf = get_string_value ("HISTFILE");
|
||||
|
||||
if (hf && *hf)
|
||||
{
|
||||
/* If the file doesn't exist, then create it. */
|
||||
if (file_exists (hf) == 0)
|
||||
{
|
||||
int file;
|
||||
file = open (hf, O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
||||
if (file != -1)
|
||||
close (file);
|
||||
}
|
||||
|
||||
/* Now actually append the lines if the history hasn't been
|
||||
stifled. If the history has been stifled, rewrite the
|
||||
history file. */
|
||||
using_history ();
|
||||
if (history_lines_this_session <= where_history () || force_append_history)
|
||||
{
|
||||
result = append_history (history_lines_this_session, hf);
|
||||
history_lines_in_file += history_lines_this_session;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = write_history (hf);
|
||||
history_lines_in_file = history_lines_this_session;
|
||||
}
|
||||
history_lines_this_session = 0;
|
||||
|
||||
sv_histsize ("HISTFILESIZE");
|
||||
}
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
/* Tell readline () that we have some text for it to edit. */
|
||||
static void
|
||||
re_edit (text)
|
||||
char *text;
|
||||
{
|
||||
if (bash_input.type == st_stdin)
|
||||
bash_re_edit (text);
|
||||
}
|
||||
#endif /* READLINE */
|
||||
|
||||
/* Return 1 if this line needs history expansion. */
|
||||
static int
|
||||
history_expansion_p (line)
|
||||
char *line;
|
||||
{
|
||||
register char *s;
|
||||
|
||||
for (s = line; *s; s++)
|
||||
if (*s == history_expansion_char || *s == history_subst_char)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do pre-processing on LINE. If PRINT_CHANGES is non-zero, then
|
||||
print the results of expanding the line if there were any changes.
|
||||
If there is an error, return NULL, otherwise the expanded line is
|
||||
returned. If ADDIT is non-zero the line is added to the history
|
||||
list after history expansion. ADDIT is just a suggestion;
|
||||
REMEMBER_ON_HISTORY can veto, and does.
|
||||
Right now this does history expansion. */
|
||||
char *
|
||||
pre_process_line (line, print_changes, addit)
|
||||
char *line;
|
||||
int print_changes, addit;
|
||||
{
|
||||
char *history_value;
|
||||
char *return_value;
|
||||
int expanded;
|
||||
|
||||
return_value = line;
|
||||
expanded = 0;
|
||||
|
||||
# if defined (BANG_HISTORY)
|
||||
/* History expand the line. If this results in no errors, then
|
||||
add that line to the history if ADDIT is non-zero. */
|
||||
if (!history_expansion_inhibited && history_expansion && history_expansion_p (line))
|
||||
{
|
||||
expanded = history_expand (line, &history_value);
|
||||
|
||||
if (expanded)
|
||||
{
|
||||
if (print_changes)
|
||||
{
|
||||
if (expanded < 0)
|
||||
internal_error ("%s", history_value);
|
||||
#if defined (READLINE)
|
||||
else if (hist_verify == 0 || expanded == 2)
|
||||
#else
|
||||
else
|
||||
#endif
|
||||
fprintf (stderr, "%s\n", history_value);
|
||||
}
|
||||
|
||||
/* If there was an error, return NULL. */
|
||||
if (expanded < 0 || expanded == 2) /* 2 == print only */
|
||||
{
|
||||
# if defined (READLINE)
|
||||
if (expanded == 2 && rl_dispatching == 0 && *history_value)
|
||||
# else
|
||||
if (expanded == 2 && *history_value)
|
||||
# endif /* !READLINE */
|
||||
maybe_add_history (history_value);
|
||||
|
||||
free (history_value);
|
||||
|
||||
# if defined (READLINE)
|
||||
/* New hack. We can allow the user to edit the
|
||||
failed history expansion. */
|
||||
if (history_reediting && expanded < 0 && rl_done)
|
||||
re_edit (line);
|
||||
# endif /* READLINE */
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
# if defined (READLINE)
|
||||
if (hist_verify && expanded == 1)
|
||||
{
|
||||
re_edit (history_value);
|
||||
return ((char *)NULL);
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
/* Let other expansions know that return_value can be free'ed,
|
||||
and that a line has been added to the history list. Note
|
||||
that we only add lines that have something in them. */
|
||||
expanded = 1;
|
||||
return_value = history_value;
|
||||
}
|
||||
# endif /* BANG_HISTORY */
|
||||
|
||||
if (addit && remember_on_history && *return_value)
|
||||
maybe_add_history (return_value);
|
||||
|
||||
#if 0
|
||||
if (expanded == 0)
|
||||
return_value = savestring (line);
|
||||
#endif
|
||||
|
||||
return (return_value);
|
||||
}
|
||||
|
||||
/* Return 1 if the first non-whitespace character in LINE is a `#', indicating
|
||||
* that the line is a shell comment. */
|
||||
static int
|
||||
shell_comment (line)
|
||||
char *line;
|
||||
{
|
||||
char *p;
|
||||
|
||||
for (p = line; p && *p && whitespace (*p); p++)
|
||||
;
|
||||
return (p && *p == '#');
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* Remove shell comments from LINE. A `#' and anything after it is a comment.
|
||||
This isn't really useful yet, since it doesn't handle quoting. */
|
||||
static char *
|
||||
filter_comments (line)
|
||||
char *line;
|
||||
{
|
||||
char *p;
|
||||
|
||||
for (p = line; p && *p && *p != '#'; p++)
|
||||
;
|
||||
if (p && *p == '#')
|
||||
*p = '\0';
|
||||
return (line);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check LINE against what HISTCONTROL says to do. Returns 1 if the line
|
||||
should be saved; 0 if it should be discarded. */
|
||||
static int
|
||||
check_history_control (line)
|
||||
char *line;
|
||||
{
|
||||
HIST_ENTRY *temp;
|
||||
int r;
|
||||
|
||||
if (history_control == 0)
|
||||
return 1;
|
||||
|
||||
/* ignorespace or ignoreboth */
|
||||
if ((history_control & HC_IGNSPACE) && *line == ' ')
|
||||
return 0;
|
||||
|
||||
/* ignoredups or ignoreboth */
|
||||
if (history_control & HC_IGNDUPS)
|
||||
{
|
||||
using_history ();
|
||||
temp = previous_history ();
|
||||
|
||||
r = (temp == 0 || STREQ (temp->line, line) == 0);
|
||||
|
||||
using_history ();
|
||||
|
||||
if (r == 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Remove all entries matching LINE from the history list. Triggered when
|
||||
HISTCONTROL includes `erasedups'. */
|
||||
static void
|
||||
hc_erasedups (line)
|
||||
char *line;
|
||||
{
|
||||
HIST_ENTRY *temp;
|
||||
int r;
|
||||
|
||||
using_history ();
|
||||
while (temp = previous_history ())
|
||||
{
|
||||
if (STREQ (temp->line, line))
|
||||
{
|
||||
r = where_history ();
|
||||
remove_history (r);
|
||||
}
|
||||
}
|
||||
using_history ();
|
||||
}
|
||||
|
||||
/* Add LINE to the history list, handling possibly multi-line compound
|
||||
commands. We note whether or not we save the first line of each command
|
||||
(which is usually the entire command and history entry), and don't add
|
||||
the second and subsequent lines of a multi-line compound command if we
|
||||
didn't save the first line. We don't usually save shell comment lines in
|
||||
compound commands in the history, because they could have the effect of
|
||||
commenting out the rest of the command when the entire command is saved as
|
||||
a single history entry (when COMMAND_ORIENTED_HISTORY is enabled). If
|
||||
LITERAL_HISTORY is set, we're saving lines in the history with embedded
|
||||
newlines, so it's OK to save comment lines. We also make sure to save
|
||||
multiple-line quoted strings or other constructs. */
|
||||
void
|
||||
maybe_add_history (line)
|
||||
char *line;
|
||||
{
|
||||
hist_last_line_added = 0;
|
||||
|
||||
/* Don't use the value of history_control to affect the second
|
||||
and subsequent lines of a multi-line command (old code did
|
||||
this only when command_oriented_history is enabled). */
|
||||
if (current_command_line_count > 1)
|
||||
{
|
||||
if (current_command_first_line_saved &&
|
||||
(literal_history || dstack.delimiter_depth != 0 || shell_comment (line) == 0))
|
||||
bash_add_history (line);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is the first line of a (possible multi-line) command. Note whether
|
||||
or not we should save the first line and remember it. */
|
||||
current_command_first_line_saved = check_add_history (line, 0);
|
||||
}
|
||||
|
||||
/* Just check LINE against HISTCONTROL and HISTIGNORE and add it to the
|
||||
history if it's OK. Used by `history -s' as well as maybe_add_history().
|
||||
Returns 1 if the line was saved in the history, 0 otherwise. */
|
||||
int
|
||||
check_add_history (line, force)
|
||||
char *line;
|
||||
int force;
|
||||
{
|
||||
if (check_history_control (line) && history_should_ignore (line) == 0)
|
||||
{
|
||||
/* We're committed to saving the line. If the user has requested it,
|
||||
remove other matching lines from the history. */
|
||||
if (history_control & HC_ERASEDUPS)
|
||||
hc_erasedups (line);
|
||||
|
||||
if (force)
|
||||
{
|
||||
really_add_history (line);
|
||||
using_history ();
|
||||
}
|
||||
else
|
||||
bash_add_history (line);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined (SYSLOG_HISTORY)
|
||||
#define SYSLOG_MAXLEN 600
|
||||
|
||||
void
|
||||
bash_syslog_history (line)
|
||||
const char *line;
|
||||
{
|
||||
char trunc[SYSLOG_MAXLEN];
|
||||
|
||||
if (strlen(line) < SYSLOG_MAXLEN)
|
||||
syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY: PID=%d UID=%d %s", getpid(), current_user.uid, line);
|
||||
else
|
||||
{
|
||||
strncpy (trunc, line, SYSLOG_MAXLEN);
|
||||
trunc[SYSLOG_MAXLEN - 1] = '\0';
|
||||
syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY (TRUNCATED): PID=%d UID=%d %s", getpid(), current_user.uid, trunc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Add a line to the history list.
|
||||
The variable COMMAND_ORIENTED_HISTORY controls the style of history
|
||||
remembering; when non-zero, and LINE is not the first line of a
|
||||
complete parser construct, append LINE to the last history line instead
|
||||
of adding it as a new line. */
|
||||
void
|
||||
bash_add_history (line)
|
||||
char *line;
|
||||
{
|
||||
int add_it, offset, curlen;
|
||||
HIST_ENTRY *current, *old;
|
||||
char *chars_to_add, *new_line;
|
||||
|
||||
add_it = 1;
|
||||
if (command_oriented_history && current_command_line_count > 1)
|
||||
{
|
||||
chars_to_add = literal_history ? "\n" : history_delimiting_chars ();
|
||||
|
||||
using_history ();
|
||||
current = previous_history ();
|
||||
|
||||
if (current)
|
||||
{
|
||||
/* If the previous line ended with an escaped newline (escaped
|
||||
with backslash, but otherwise unquoted), then remove the quoted
|
||||
newline, since that is what happens when the line is parsed. */
|
||||
curlen = strlen (current->line);
|
||||
|
||||
if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\\' &&
|
||||
current->line[curlen - 2] != '\\')
|
||||
{
|
||||
current->line[curlen - 1] = '\0';
|
||||
curlen--;
|
||||
chars_to_add = "";
|
||||
}
|
||||
|
||||
new_line = (char *)xmalloc (1
|
||||
+ curlen
|
||||
+ strlen (line)
|
||||
+ strlen (chars_to_add));
|
||||
sprintf (new_line, "%s%s%s", current->line, chars_to_add, line);
|
||||
offset = where_history ();
|
||||
old = replace_history_entry (offset, new_line, current->data);
|
||||
free (new_line);
|
||||
|
||||
if (old)
|
||||
free_history_entry (old);
|
||||
|
||||
add_it = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (add_it)
|
||||
really_add_history (line);
|
||||
|
||||
#if defined (SYSLOG_HISTORY)
|
||||
bash_syslog_history (line);
|
||||
#endif
|
||||
|
||||
using_history ();
|
||||
}
|
||||
|
||||
static void
|
||||
really_add_history (line)
|
||||
char *line;
|
||||
{
|
||||
hist_last_line_added = 1;
|
||||
hist_last_line_pushed = 0;
|
||||
add_history (line);
|
||||
history_lines_this_session++;
|
||||
}
|
||||
|
||||
int
|
||||
history_number ()
|
||||
{
|
||||
using_history ();
|
||||
return (remember_on_history ? history_base + where_history () : 1);
|
||||
}
|
||||
|
||||
static int
|
||||
should_expand (s)
|
||||
char *s;
|
||||
{
|
||||
char *p;
|
||||
|
||||
for (p = s; p && *p; p++)
|
||||
{
|
||||
if (*p == '\\')
|
||||
p++;
|
||||
else if (*p == '&')
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
histignore_item_func (ign)
|
||||
struct ign *ign;
|
||||
{
|
||||
if (should_expand (ign->val))
|
||||
ign->flags |= HIGN_EXPAND;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
setup_history_ignore (varname)
|
||||
char *varname;
|
||||
{
|
||||
setup_ignore_patterns (&histignore);
|
||||
}
|
||||
|
||||
static HIST_ENTRY *
|
||||
last_history_entry ()
|
||||
{
|
||||
HIST_ENTRY *he;
|
||||
|
||||
using_history ();
|
||||
he = previous_history ();
|
||||
using_history ();
|
||||
return he;
|
||||
}
|
||||
|
||||
char *
|
||||
last_history_line ()
|
||||
{
|
||||
HIST_ENTRY *he;
|
||||
|
||||
he = last_history_entry ();
|
||||
if (he == 0)
|
||||
return ((char *)NULL);
|
||||
return he->line;
|
||||
}
|
||||
|
||||
static char *
|
||||
expand_histignore_pattern (pat)
|
||||
char *pat;
|
||||
{
|
||||
HIST_ENTRY *phe;
|
||||
char *ret;
|
||||
|
||||
phe = last_history_entry ();
|
||||
|
||||
if (phe == (HIST_ENTRY *)0)
|
||||
return (savestring (pat));
|
||||
|
||||
ret = strcreplace (pat, '&', phe->line, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return 1 if we should not put LINE into the history according to the
|
||||
patterns in HISTIGNORE. */
|
||||
static int
|
||||
history_should_ignore (line)
|
||||
char *line;
|
||||
{
|
||||
register int i, match;
|
||||
char *npat;
|
||||
|
||||
if (histignore.num_ignores == 0)
|
||||
return 0;
|
||||
|
||||
for (i = match = 0; i < histignore.num_ignores; i++)
|
||||
{
|
||||
if (histignore.ignores[i].flags & HIGN_EXPAND)
|
||||
npat = expand_histignore_pattern (histignore.ignores[i].val);
|
||||
else
|
||||
npat = histignore.ignores[i].val;
|
||||
|
||||
match = strmatch (npat, line, FNMATCH_EXTFLAG) != FNM_NOMATCH;
|
||||
|
||||
if (histignore.ignores[i].flags & HIGN_EXPAND)
|
||||
free (npat);
|
||||
|
||||
if (match)
|
||||
break;
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
#endif /* HISTORY */
|
||||
+12
-1
@@ -184,6 +184,7 @@ int dont_save_function_defs;
|
||||
extern int current_command_line_count;
|
||||
|
||||
extern struct dstack dstack;
|
||||
extern int parser_state;
|
||||
|
||||
static int bash_history_inhibit_expansion __P((char *, int));
|
||||
#if defined (READLINE)
|
||||
@@ -731,7 +732,8 @@ bash_add_history (line)
|
||||
add_it = 1;
|
||||
if (command_oriented_history && current_command_line_count > 1)
|
||||
{
|
||||
chars_to_add = literal_history ? "\n" : history_delimiting_chars ();
|
||||
chars_to_add = literal_history ? "\n" : history_delimiting_chars (line);
|
||||
itrace("bash_add_history: `%s' PST_HEREDOC = %d chars_to_add = `%s'", line, (parser_state&PST_HEREDOC), chars_to_add);
|
||||
|
||||
using_history ();
|
||||
current = previous_history ();
|
||||
@@ -751,6 +753,15 @@ bash_add_history (line)
|
||||
chars_to_add = "";
|
||||
}
|
||||
|
||||
#if 1 /* XXX - bash-4.2 */
|
||||
/* If we're not in some kind of quoted construct, the current history
|
||||
entry ends with a newline, and we're going to add a semicolon,
|
||||
don't. In some cases, it results in a syntax error (e.g., before
|
||||
a close brace), and it should not be needed. */
|
||||
if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\n' && *chars_to_add == ';')
|
||||
chars_to_add++;
|
||||
#endif
|
||||
|
||||
new_line = (char *)xmalloc (1
|
||||
+ curlen
|
||||
+ strlen (line)
|
||||
|
||||
@@ -863,6 +863,7 @@ edit_and_execute_command (count, c, editing_mode, edit_command)
|
||||
{
|
||||
char *command, *metaval;
|
||||
int r, cclc, rrs, metaflag;
|
||||
sh_parser_state_t ps;
|
||||
|
||||
rrs = rl_readline_state;
|
||||
cclc = current_command_line_count;
|
||||
@@ -897,7 +898,9 @@ edit_and_execute_command (count, c, editing_mode, edit_command)
|
||||
yet. */
|
||||
if (rl_deprep_term_function)
|
||||
(*rl_deprep_term_function) ();
|
||||
save_parser_state (&ps);
|
||||
r = parse_and_execute (command, (editing_mode == VI_EDITING_MODE) ? "v" : "C-xC-e", SEVAL_NOHIST);
|
||||
restore_parser_state (&ps);
|
||||
if (rl_prep_term_function)
|
||||
(*rl_prep_term_function) (metaflag);
|
||||
|
||||
|
||||
@@ -1680,11 +1680,7 @@ globword:
|
||||
a single match (multiple matches that end up reducing the number of
|
||||
characters in the common prefix are bad) will ever be returned on
|
||||
regular completion. */
|
||||
#if 1
|
||||
if (globpat)
|
||||
#else
|
||||
if (glob_pattern_p (hint))
|
||||
#endif
|
||||
{
|
||||
if (state == 0)
|
||||
{
|
||||
|
||||
+1
-1
@@ -117,7 +117,7 @@ extern int errno;
|
||||
else if (have_fieldwidth) \
|
||||
nw = vflag ? vbprintf (f, fieldwidth, func) : printf (f, fieldwidth, func); \
|
||||
else if (have_precision) \
|
||||
nw = vflag ? vbprintf (f, precision, func) : printf (f, fieldwidth, func); \
|
||||
nw = vflag ? vbprintf (f, precision, func) : printf (f, precision, func); \
|
||||
else \
|
||||
nw = vflag ? vbprintf (f, func) : printf (f, func); \
|
||||
tw += nw; \
|
||||
|
||||
+15
-1
@@ -127,7 +127,10 @@ trap_builtin (list)
|
||||
if (list_signal_names)
|
||||
return (sh_chkwrite (display_signal_list ((WORD_LIST *)NULL, 1)));
|
||||
else if (display || list == 0)
|
||||
return (sh_chkwrite (display_traps (list)));
|
||||
{
|
||||
initialize_terminating_signals ();
|
||||
return (sh_chkwrite (display_traps (list)));
|
||||
}
|
||||
else
|
||||
{
|
||||
char *first_arg;
|
||||
@@ -199,6 +202,8 @@ trap_builtin (list)
|
||||
switch (sig)
|
||||
{
|
||||
case SIGINT:
|
||||
/* XXX - should we do this if original disposition
|
||||
was SIG_IGN? */
|
||||
if (interactive)
|
||||
set_signal_handler (SIGINT, sigint_sighandler);
|
||||
else
|
||||
@@ -240,10 +245,19 @@ showtrap (i)
|
||||
char *t, *p, *sn;
|
||||
|
||||
p = trap_list[i];
|
||||
#if 1
|
||||
if (p == (char *)DEFAULT_SIG)
|
||||
return;
|
||||
|
||||
t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p);
|
||||
#else
|
||||
if (p == (char *)DEFAULT_SIG && signal_is_hard_ignored (i) == 0)
|
||||
return;
|
||||
else if (signal_is_hard_ignored (i))
|
||||
t = (char *)NULL;
|
||||
else
|
||||
t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p);
|
||||
#endif
|
||||
sn = signal_name (i);
|
||||
/* Make sure that signals whose names are unknown (for whatever reason)
|
||||
are printed as signal numbers. */
|
||||
|
||||
+27
-4
@@ -93,7 +93,7 @@ static int display_traps __P((WORD_LIST *));
|
||||
#define REVERT 1 /* Revert to this signals original value. */
|
||||
#define IGNORE 2 /* Ignore this signal. */
|
||||
|
||||
extern int posixly_correct;
|
||||
extern int posixly_correct, subshell_environment;
|
||||
|
||||
int
|
||||
trap_builtin (list)
|
||||
@@ -103,6 +103,7 @@ trap_builtin (list)
|
||||
|
||||
list_signal_names = display = 0;
|
||||
result = EXECUTION_SUCCESS;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "lp")) != -1)
|
||||
{
|
||||
@@ -126,7 +127,10 @@ trap_builtin (list)
|
||||
if (list_signal_names)
|
||||
return (sh_chkwrite (display_signal_list ((WORD_LIST *)NULL, 1)));
|
||||
else if (display || list == 0)
|
||||
return (sh_chkwrite (display_traps (list)));
|
||||
{
|
||||
initialize_terminating_signals ();
|
||||
return (sh_chkwrite (display_traps (list)));
|
||||
}
|
||||
else
|
||||
{
|
||||
char *first_arg;
|
||||
@@ -163,6 +167,16 @@ trap_builtin (list)
|
||||
operation = REVERT;
|
||||
}
|
||||
|
||||
/* If we're in a command substitution, we haven't freed the trap strings
|
||||
(though we reset the signal handlers). If we're setting a trap to
|
||||
handle a signal here, free the rest of the trap strings since they
|
||||
don't apply any more. */
|
||||
if (subshell_environment & SUBSHELL_RESETTRAP)
|
||||
{
|
||||
free_trap_strings ();
|
||||
subshell_environment &= ~SUBSHELL_RESETTRAP;
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
sig = decode_signal (list->word->word, opt);
|
||||
@@ -188,6 +202,8 @@ trap_builtin (list)
|
||||
switch (sig)
|
||||
{
|
||||
case SIGINT:
|
||||
/* XXX - should we do this if original disposition
|
||||
was SIG_IGN? */
|
||||
if (interactive)
|
||||
set_signal_handler (SIGINT, sigint_sighandler);
|
||||
else
|
||||
@@ -229,10 +245,17 @@ showtrap (i)
|
||||
char *t, *p, *sn;
|
||||
|
||||
p = trap_list[i];
|
||||
#if 1
|
||||
if (p == (char *)DEFAULT_SIG)
|
||||
return;
|
||||
|
||||
t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p);
|
||||
#else
|
||||
if (p == (char *)DEFAULT_SIG && signal_is_hard_ignored (i) == 0)
|
||||
return;
|
||||
else if (signal_is_hard_ignored (i))
|
||||
t = (char *)NULL;
|
||||
else
|
||||
#endif
|
||||
t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p);
|
||||
sn = signal_name (i);
|
||||
/* Make sure that signals whose names are unknown (for whatever reason)
|
||||
are printed as signal numbers. */
|
||||
|
||||
@@ -555,6 +555,9 @@
|
||||
/* Define if you have the eaccess function. */
|
||||
#undef HAVE_EACCESS
|
||||
|
||||
/* Define if you have the faccessat function. */
|
||||
#undef HAVE_FACCESSAT
|
||||
|
||||
/* Define if you have the fcntl function. */
|
||||
#undef HAVE_FCNTL
|
||||
|
||||
|
||||
@@ -680,6 +680,9 @@
|
||||
/* Define if you have the mbscmp function. */
|
||||
#undef HAVE_MBSCMP
|
||||
|
||||
/* Define if you have the mbsnrtowcs function. */
|
||||
#undef HAVE_MBSNRTOWCS
|
||||
|
||||
/* Define if you have the mbsrtowcs function. */
|
||||
#undef HAVE_MBSRTOWCS
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#! /bin/sh
|
||||
# From configure.in for Bash 4.1, version 4.022.
|
||||
# From configure.in for Bash 4.1, version 4.023.
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.63 for bash 4.1-maint.
|
||||
#
|
||||
@@ -13577,7 +13577,8 @@ done
|
||||
|
||||
|
||||
|
||||
for ac_func in bcopy bzero confstr fnmatch \
|
||||
|
||||
for ac_func in bcopy bzero confstr faccessat fnmatch \
|
||||
getaddrinfo gethostbyname getservbyname getservent inet_aton \
|
||||
memmove pathconf putenv raise regcomp regexec \
|
||||
setenv setlinebuf setlocale setvbuf siginterrupt strchr \
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@ dnl Process this file with autoconf to produce a configure script.
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AC_REVISION([for Bash 4.1, version 4.022])dnl
|
||||
AC_REVISION([for Bash 4.1, version 4.023])dnl
|
||||
|
||||
define(bashvers, 4.1)
|
||||
define(relstatus, maint)
|
||||
@@ -727,7 +727,7 @@ AC_CHECK_FUNCS(dup2 eaccess fcntl getdtablesize getgroups gethostname \
|
||||
AC_REPLACE_FUNCS(rename)
|
||||
|
||||
dnl checks for c library functions
|
||||
AC_CHECK_FUNCS(bcopy bzero confstr fnmatch \
|
||||
AC_CHECK_FUNCS(bcopy bzero confstr faccessat fnmatch \
|
||||
getaddrinfo gethostbyname getservbyname getservent inet_aton \
|
||||
memmove pathconf putenv raise regcomp regexec \
|
||||
setenv setlinebuf setlocale setvbuf siginterrupt strchr \
|
||||
|
||||
+3
-2
@@ -5,7 +5,7 @@ dnl report bugs to chet@po.cwru.edu
|
||||
dnl
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
# Copyright (C) 1987-2009 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1987-2010 Free Software Foundation, Inc.
|
||||
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -21,7 +21,7 @@ dnl Process this file with autoconf to produce a configure script.
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AC_REVISION([for Bash 4.1, version 4.021])dnl
|
||||
AC_REVISION([for Bash 4.1, version 4.023])dnl
|
||||
|
||||
define(bashvers, 4.1)
|
||||
define(relstatus, maint)
|
||||
@@ -740,6 +740,7 @@ AC_REPLACE_FUNCS(getcwd memset)
|
||||
AC_REPLACE_FUNCS(strcasecmp strcasestr strerror strftime strnlen strpbrk strstr)
|
||||
AC_REPLACE_FUNCS(strtod strtol strtoul strtoll strtoull strtoimax strtoumax)
|
||||
AC_REPLACE_FUNCS(dprintf)
|
||||
AC_REPLACE_FUNCS(strchrnul)
|
||||
|
||||
AC_CHECK_DECLS([confstr])
|
||||
AC_CHECK_DECLS([printf])
|
||||
|
||||
@@ -4542,6 +4542,7 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
reset_terminating_signals (); /* XXX */
|
||||
/* Cancel traps, in trap.c. */
|
||||
restore_original_signals ();
|
||||
|
||||
|
||||
@@ -1219,6 +1219,7 @@ time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close)
|
||||
|
||||
posix_time = (command->flags & CMD_TIME_POSIX);
|
||||
|
||||
#if 0 /* XXX - bash-4.2 */
|
||||
nullcmd = (command == 0) || (command->type == cm_simple && command->value.Simple->words == 0 && command->value.Simple->redirects == 0);
|
||||
if (posixly_correct && nullcmd)
|
||||
{
|
||||
@@ -1232,6 +1233,7 @@ time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close)
|
||||
tbefore = shell_start_time;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
old_flags = command->flags;
|
||||
command->flags &= ~(CMD_TIME_PIPELINE|CMD_TIME_POSIX);
|
||||
@@ -1287,9 +1289,11 @@ time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close)
|
||||
time_format = POSIX_TIMEFORMAT;
|
||||
else if ((time_format = get_string_value ("TIMEFORMAT")) == 0)
|
||||
{
|
||||
#if 0 /* XXX - bash-4.2 */
|
||||
if (posixly_correct && nullcmd)
|
||||
time_format = "user\t%2lU\nsys\t%2lS";
|
||||
else
|
||||
#endif
|
||||
time_format = BASH_TIMEFORMAT;
|
||||
}
|
||||
if (time_format && *time_format)
|
||||
|
||||
@@ -114,7 +114,7 @@ extern int get_current_prompt_level __P((void));
|
||||
extern void set_current_prompt_level __P((int));
|
||||
|
||||
#if defined (HISTORY)
|
||||
extern char *history_delimiting_chars __P((void));
|
||||
extern char *history_delimiting_chars __P((const char *));
|
||||
#endif
|
||||
|
||||
/* Declarations for functions defined in locale.c */
|
||||
|
||||
@@ -327,6 +327,11 @@ extern int strcasecmp __P((const char *, const char *));
|
||||
extern char *strcasestr __P((const char *, const char *));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strchrnul.c */
|
||||
#if ! HAVE_STRCHRNUL
|
||||
extern char *strchrnul __P((const char *, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strerror.c */
|
||||
#if !defined (HAVE_STRERROR) && !defined (strerror)
|
||||
extern char *strerror __P((int));
|
||||
|
||||
@@ -2094,9 +2094,9 @@ rl_filename_completion_function (text, state)
|
||||
else if (rl_completion_found_quote && rl_filename_dequoting_function)
|
||||
{
|
||||
/* delete single and double quotes */
|
||||
temp = (*rl_filename_dequoting_function) (users_dirname, rl_completion_quote_character);
|
||||
free (users_dirname);
|
||||
users_dirname = temp;
|
||||
temp = (*rl_filename_dequoting_function) (dirname, rl_completion_quote_character);
|
||||
free (dirname);
|
||||
dirname = temp;
|
||||
}
|
||||
directory = opendir (dirname);
|
||||
|
||||
|
||||
@@ -2304,14 +2304,14 @@ rl_old_menu_complete (count, invoking_key)
|
||||
|
||||
if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0)
|
||||
{
|
||||
rl_ding ();
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
FREE (orig_text);
|
||||
orig_text = (char *)0;
|
||||
completion_changed_buffer = 0;
|
||||
RL_UNSETSTATE(RL_STATE_COMPLETING);
|
||||
return (0);
|
||||
completion_changed_buffer = 0;
|
||||
RL_UNSETSTATE(RL_STATE_COMPLETING);
|
||||
return (0);
|
||||
}
|
||||
|
||||
RL_UNSETSTATE(RL_STATE_COMPLETING);
|
||||
@@ -2428,14 +2428,14 @@ rl_menu_complete (count, ignore)
|
||||
|
||||
if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0)
|
||||
{
|
||||
rl_ding ();
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
FREE (orig_text);
|
||||
orig_text = (char *)0;
|
||||
completion_changed_buffer = 0;
|
||||
RL_UNSETSTATE(RL_STATE_COMPLETING);
|
||||
return (0);
|
||||
completion_changed_buffer = 0;
|
||||
RL_UNSETSTATE(RL_STATE_COMPLETING);
|
||||
return (0);
|
||||
}
|
||||
|
||||
RL_UNSETSTATE(RL_STATE_COMPLETING);
|
||||
|
||||
@@ -0,0 +1,671 @@
|
||||
/* signals.c -- signal handling support for readline. */
|
||||
|
||||
/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Readline Library (Readline), a library
|
||||
for reading lines of text with interactive input and history editing.
|
||||
|
||||
Readline is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Readline 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 Readline. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define READLINE_LIBRARY
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h> /* Just for NULL. Yuck. */
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
/* System-specific feature definitions and include files. */
|
||||
#include "rldefs.h"
|
||||
|
||||
#if defined (GWINSZ_IN_SYS_IOCTL)
|
||||
# include <sys/ioctl.h>
|
||||
#endif /* GWINSZ_IN_SYS_IOCTL */
|
||||
|
||||
/* Some standard library routines. */
|
||||
#include "readline.h"
|
||||
#include "history.h"
|
||||
|
||||
#include "rlprivate.h"
|
||||
|
||||
#if defined (HANDLE_SIGNALS)
|
||||
|
||||
#if !defined (RETSIGTYPE)
|
||||
# if defined (VOID_SIGHANDLER)
|
||||
# define RETSIGTYPE void
|
||||
# else
|
||||
# define RETSIGTYPE int
|
||||
# endif /* !VOID_SIGHANDLER */
|
||||
#endif /* !RETSIGTYPE */
|
||||
|
||||
#if defined (VOID_SIGHANDLER)
|
||||
# define SIGHANDLER_RETURN return
|
||||
#else
|
||||
# define SIGHANDLER_RETURN return (0)
|
||||
#endif
|
||||
|
||||
/* This typedef is equivalent to the one for Function; it allows us
|
||||
to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */
|
||||
typedef RETSIGTYPE SigHandler ();
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
typedef struct sigaction sighandler_cxt;
|
||||
# define rl_sigaction(s, nh, oh) sigaction(s, nh, oh)
|
||||
#else
|
||||
typedef struct { SigHandler *sa_handler; int sa_mask, sa_flags; } sighandler_cxt;
|
||||
# define sigemptyset(m)
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
#ifndef SA_RESTART
|
||||
# define SA_RESTART 0
|
||||
#endif
|
||||
|
||||
static SigHandler *rl_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *));
|
||||
static void rl_maybe_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *));
|
||||
|
||||
static RETSIGTYPE rl_signal_handler PARAMS((int));
|
||||
static RETSIGTYPE _rl_handle_signal PARAMS((int));
|
||||
|
||||
/* Exported variables for use by applications. */
|
||||
|
||||
/* If non-zero, readline will install its own signal handlers for
|
||||
SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */
|
||||
int rl_catch_signals = 1;
|
||||
|
||||
/* If non-zero, readline will install a signal handler for SIGWINCH. */
|
||||
#ifdef SIGWINCH
|
||||
int rl_catch_sigwinch = 1;
|
||||
#else
|
||||
int rl_catch_sigwinch = 0; /* for the readline state struct in readline.c */
|
||||
#endif
|
||||
|
||||
/* Private variables. */
|
||||
int _rl_interrupt_immediately = 0;
|
||||
int volatile _rl_caught_signal = 0; /* should be sig_atomic_t, but that requires including <signal.h> everywhere */
|
||||
|
||||
/* If non-zero, print characters corresponding to received signals as long as
|
||||
the user has indicated his desire to do so (_rl_echo_control_chars). */
|
||||
int _rl_echoctl = 0;
|
||||
|
||||
int _rl_intr_char = 0;
|
||||
int _rl_quit_char = 0;
|
||||
int _rl_susp_char = 0;
|
||||
|
||||
static int signals_set_flag;
|
||||
static int sigwinch_set_flag;
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Signal Handling */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
static sighandler_cxt old_int, old_term, old_alrm, old_quit;
|
||||
#if defined (SIGTSTP)
|
||||
static sighandler_cxt old_tstp, old_ttou, old_ttin;
|
||||
#endif
|
||||
#if defined (SIGWINCH)
|
||||
static sighandler_cxt old_winch;
|
||||
#endif
|
||||
|
||||
/* Readline signal handler functions. */
|
||||
|
||||
/* Called from RL_CHECK_SIGNALS() macro */
|
||||
RETSIGTYPE
|
||||
_rl_signal_handler (sig)
|
||||
{
|
||||
_rl_caught_signal = 0; /* XXX */
|
||||
|
||||
_rl_handle_signal (sig);
|
||||
SIGHANDLER_RETURN;
|
||||
}
|
||||
|
||||
static RETSIGTYPE
|
||||
rl_signal_handler (sig)
|
||||
int sig;
|
||||
{
|
||||
fprintf(stderr, "rl_signal_handler: caught %d", sig);
|
||||
if (_rl_interrupt_immediately || RL_ISSTATE(RL_STATE_CALLBACK))
|
||||
{
|
||||
_rl_interrupt_immediately = 0;
|
||||
_rl_handle_signal (sig);
|
||||
}
|
||||
else
|
||||
_rl_caught_signal = sig;
|
||||
|
||||
SIGHANDLER_RETURN;
|
||||
}
|
||||
|
||||
static RETSIGTYPE
|
||||
_rl_handle_signal (sig)
|
||||
int sig;
|
||||
{
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigset_t set;
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
# if defined (HAVE_BSD_SIGNALS)
|
||||
long omask;
|
||||
# else /* !HAVE_BSD_SIGNALS */
|
||||
sighandler_cxt dummy_cxt; /* needed for rl_set_sighandler call */
|
||||
# endif /* !HAVE_BSD_SIGNALS */
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
RL_SETSTATE(RL_STATE_SIGHANDLER);
|
||||
|
||||
#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS)
|
||||
/* Since the signal will not be blocked while we are in the signal
|
||||
handler, ignore it until rl_clear_signals resets the catcher. */
|
||||
# if defined (SIGALRM)
|
||||
if (sig == SIGINT || sig == SIGALRM)
|
||||
# else
|
||||
if (sig == SIGINT)
|
||||
# endif
|
||||
rl_set_sighandler (sig, SIG_IGN, &dummy_cxt);
|
||||
#endif /* !HAVE_BSD_SIGNALS && !HAVE_POSIX_SIGNALS */
|
||||
|
||||
switch (sig)
|
||||
{
|
||||
case SIGINT:
|
||||
_rl_reset_completion_state ();
|
||||
rl_free_line_state ();
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case SIGTERM:
|
||||
#if defined (SIGTSTP)
|
||||
case SIGTSTP:
|
||||
case SIGTTOU:
|
||||
case SIGTTIN:
|
||||
#endif /* SIGTSTP */
|
||||
#if defined (SIGALRM)
|
||||
case SIGALRM:
|
||||
#endif
|
||||
#if defined (SIGQUIT)
|
||||
case SIGQUIT:
|
||||
#endif
|
||||
rl_echo_signal_char (sig);
|
||||
rl_cleanup_after_signal ();
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigemptyset (&set);
|
||||
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &set);
|
||||
sigdelset (&set, sig);
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
# if defined (HAVE_BSD_SIGNALS)
|
||||
omask = sigblock (0);
|
||||
# endif /* HAVE_BSD_SIGNALS */
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
#if defined (__EMX__)
|
||||
signal (sig, SIG_ACK);
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_KILL)
|
||||
kill (getpid (), sig);
|
||||
#else
|
||||
raise (sig); /* assume we have raise */
|
||||
#endif
|
||||
|
||||
/* Let the signal that we just sent through. */
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL);
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
# if defined (HAVE_BSD_SIGNALS)
|
||||
sigsetmask (omask & ~(sigmask (sig)));
|
||||
# endif /* HAVE_BSD_SIGNALS */
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
rl_reset_after_signal ();
|
||||
}
|
||||
|
||||
RL_UNSETSTATE(RL_STATE_SIGHANDLER);
|
||||
SIGHANDLER_RETURN;
|
||||
}
|
||||
|
||||
#if defined (SIGWINCH)
|
||||
static RETSIGTYPE
|
||||
rl_sigwinch_handler (sig)
|
||||
int sig;
|
||||
{
|
||||
SigHandler *oh;
|
||||
|
||||
#if defined (MUST_REINSTALL_SIGHANDLERS)
|
||||
sighandler_cxt dummy_winch;
|
||||
|
||||
/* We don't want to change old_winch -- it holds the state of SIGWINCH
|
||||
disposition set by the calling application. We need this state
|
||||
because we call the application's SIGWINCH handler after updating
|
||||
our own idea of the screen size. */
|
||||
rl_set_sighandler (SIGWINCH, rl_sigwinch_handler, &dummy_winch);
|
||||
#endif
|
||||
|
||||
RL_SETSTATE(RL_STATE_SIGHANDLER);
|
||||
rl_resize_terminal ();
|
||||
|
||||
/* If another sigwinch handler has been installed, call it. */
|
||||
oh = (SigHandler *)old_winch.sa_handler;
|
||||
if (oh && oh != (SigHandler *)SIG_IGN && oh != (SigHandler *)SIG_DFL)
|
||||
(*oh) (sig);
|
||||
|
||||
RL_UNSETSTATE(RL_STATE_SIGHANDLER);
|
||||
SIGHANDLER_RETURN;
|
||||
}
|
||||
#endif /* SIGWINCH */
|
||||
|
||||
/* Functions to manage signal handling. */
|
||||
|
||||
#if !defined (HAVE_POSIX_SIGNALS)
|
||||
static int
|
||||
rl_sigaction (sig, nh, oh)
|
||||
int sig;
|
||||
sighandler_cxt *nh, *oh;
|
||||
{
|
||||
oh->sa_handler = signal (sig, nh->sa_handler);
|
||||
return 0;
|
||||
}
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
/* Set up a readline-specific signal handler, saving the old signal
|
||||
information in OHANDLER. Return the old signal handler, like
|
||||
signal(). */
|
||||
static SigHandler *
|
||||
rl_set_sighandler (sig, handler, ohandler)
|
||||
int sig;
|
||||
SigHandler *handler;
|
||||
sighandler_cxt *ohandler;
|
||||
{
|
||||
sighandler_cxt old_handler;
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
struct sigaction act;
|
||||
|
||||
act.sa_handler = handler;
|
||||
# if defined (SIGWINCH)
|
||||
act.sa_flags = (sig == SIGWINCH) ? SA_RESTART : 0;
|
||||
# else
|
||||
act.sa_flags = 0;
|
||||
# endif /* SIGWINCH */
|
||||
sigemptyset (&act.sa_mask);
|
||||
sigemptyset (&ohandler->sa_mask);
|
||||
sigaction (sig, &act, &old_handler);
|
||||
#else
|
||||
old_handler.sa_handler = (SigHandler *)signal (sig, handler);
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
/* XXX -- assume we have memcpy */
|
||||
/* If rl_set_signals is called twice in a row, don't set the old handler to
|
||||
rl_signal_handler, because that would cause infinite recursion. */
|
||||
if (handler != rl_signal_handler || old_handler.sa_handler != rl_signal_handler)
|
||||
memcpy (ohandler, &old_handler, sizeof (sighandler_cxt));
|
||||
|
||||
return (ohandler->sa_handler);
|
||||
}
|
||||
|
||||
static void
|
||||
rl_maybe_set_sighandler (sig, handler, ohandler)
|
||||
int sig;
|
||||
SigHandler *handler;
|
||||
sighandler_cxt *ohandler;
|
||||
{
|
||||
sighandler_cxt dummy;
|
||||
SigHandler *oh;
|
||||
|
||||
sigemptyset (&dummy.sa_mask);
|
||||
oh = rl_set_sighandler (sig, handler, ohandler);
|
||||
if (oh == (SigHandler *)SIG_IGN)
|
||||
rl_sigaction (sig, ohandler, &dummy);
|
||||
}
|
||||
|
||||
int
|
||||
rl_set_signals ()
|
||||
{
|
||||
sighandler_cxt dummy;
|
||||
SigHandler *oh;
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
static int sigmask_set = 0;
|
||||
static sigset_t bset, oset;
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
if (rl_catch_signals && sigmask_set == 0)
|
||||
{
|
||||
sigemptyset (&bset);
|
||||
|
||||
sigaddset (&bset, SIGINT);
|
||||
sigaddset (&bset, SIGTERM);
|
||||
#if defined (SIGQUIT)
|
||||
sigaddset (&bset, SIGQUIT);
|
||||
#endif
|
||||
#if defined (SIGALRM)
|
||||
sigaddset (&bset, SIGALRM);
|
||||
#endif
|
||||
#if defined (SIGTSTP)
|
||||
sigaddset (&bset, SIGTSTP);
|
||||
#endif
|
||||
#if defined (SIGTTIN)
|
||||
sigaddset (&bset, SIGTTIN);
|
||||
#endif
|
||||
#if defined (SIGTTOU)
|
||||
sigaddset (&bset, SIGTTOU);
|
||||
#endif
|
||||
sigmask_set = 1;
|
||||
}
|
||||
#endif /* HAVE_POSIX_SIGNALS */
|
||||
|
||||
if (rl_catch_signals && signals_set_flag == 0)
|
||||
{
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigemptyset (&oset);
|
||||
sigprocmask (SIG_BLOCK, &bset, &oset);
|
||||
#endif
|
||||
|
||||
rl_maybe_set_sighandler (SIGINT, rl_signal_handler, &old_int);
|
||||
rl_maybe_set_sighandler (SIGTERM, rl_signal_handler, &old_term);
|
||||
#if defined (SIGQUIT)
|
||||
rl_maybe_set_sighandler (SIGQUIT, rl_signal_handler, &old_quit);
|
||||
#endif
|
||||
|
||||
#if defined (SIGALRM)
|
||||
oh = rl_set_sighandler (SIGALRM, rl_signal_handler, &old_alrm);
|
||||
if (oh == (SigHandler *)SIG_IGN)
|
||||
rl_sigaction (SIGALRM, &old_alrm, &dummy);
|
||||
#if defined (HAVE_POSIX_SIGNALS) && defined (SA_RESTART)
|
||||
/* If the application using readline has already installed a signal
|
||||
handler with SA_RESTART, SIGALRM will cause reads to be restarted
|
||||
automatically, so readline should just get out of the way. Since
|
||||
we tested for SIG_IGN above, we can just test for SIG_DFL here. */
|
||||
if (oh != (SigHandler *)SIG_DFL && (old_alrm.sa_flags & SA_RESTART))
|
||||
rl_sigaction (SIGALRM, &old_alrm, &dummy);
|
||||
#endif /* HAVE_POSIX_SIGNALS */
|
||||
#endif /* SIGALRM */
|
||||
|
||||
#if defined (SIGTSTP)
|
||||
rl_maybe_set_sighandler (SIGTSTP, rl_signal_handler, &old_tstp);
|
||||
#endif /* SIGTSTP */
|
||||
|
||||
#if defined (SIGTTOU)
|
||||
rl_maybe_set_sighandler (SIGTTOU, rl_signal_handler, &old_ttou);
|
||||
#endif /* SIGTTOU */
|
||||
|
||||
#if defined (SIGTTIN)
|
||||
rl_maybe_set_sighandler (SIGTTIN, rl_signal_handler, &old_ttin);
|
||||
#endif /* SIGTTIN */
|
||||
|
||||
signals_set_flag = 1;
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined (SIGWINCH)
|
||||
if (rl_catch_sigwinch && sigwinch_set_flag == 0)
|
||||
{
|
||||
rl_maybe_set_sighandler (SIGWINCH, rl_sigwinch_handler, &old_winch);
|
||||
sigwinch_set_flag = 1;
|
||||
}
|
||||
#endif /* SIGWINCH */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rl_clear_signals ()
|
||||
{
|
||||
sighandler_cxt dummy;
|
||||
|
||||
if (rl_catch_signals && signals_set_flag == 1)
|
||||
{
|
||||
sigemptyset (&dummy.sa_mask);
|
||||
|
||||
rl_sigaction (SIGINT, &old_int, &dummy);
|
||||
rl_sigaction (SIGTERM, &old_term, &dummy);
|
||||
#if defined (SIGQUIT)
|
||||
rl_sigaction (SIGQUIT, &old_quit, &dummy);
|
||||
#endif
|
||||
#if defined (SIGALRM)
|
||||
rl_sigaction (SIGALRM, &old_alrm, &dummy);
|
||||
#endif
|
||||
|
||||
#if defined (SIGTSTP)
|
||||
rl_sigaction (SIGTSTP, &old_tstp, &dummy);
|
||||
#endif /* SIGTSTP */
|
||||
|
||||
#if defined (SIGTTOU)
|
||||
rl_sigaction (SIGTTOU, &old_ttou, &dummy);
|
||||
#endif /* SIGTTOU */
|
||||
|
||||
#if defined (SIGTTIN)
|
||||
rl_sigaction (SIGTTIN, &old_ttin, &dummy);
|
||||
#endif /* SIGTTIN */
|
||||
|
||||
signals_set_flag = 0;
|
||||
}
|
||||
|
||||
#if defined (SIGWINCH)
|
||||
if (rl_catch_sigwinch && sigwinch_set_flag == 1)
|
||||
{
|
||||
sigemptyset (&dummy.sa_mask);
|
||||
rl_sigaction (SIGWINCH, &old_winch, &dummy);
|
||||
sigwinch_set_flag = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Clean up the terminal and readline state after catching a signal, before
|
||||
resending it to the calling application. */
|
||||
void
|
||||
rl_cleanup_after_signal ()
|
||||
{
|
||||
_rl_clean_up_for_exit ();
|
||||
if (rl_deprep_term_function)
|
||||
(*rl_deprep_term_function) ();
|
||||
rl_clear_pending_input ();
|
||||
rl_clear_signals ();
|
||||
}
|
||||
|
||||
/* Reset the terminal and readline state after a signal handler returns. */
|
||||
void
|
||||
rl_reset_after_signal ()
|
||||
{
|
||||
if (rl_prep_term_function)
|
||||
(*rl_prep_term_function) (_rl_meta_flag);
|
||||
rl_set_signals ();
|
||||
}
|
||||
|
||||
/* Free up the readline variable line state for the current line (undo list,
|
||||
any partial history entry, any keyboard macros in progress, and any
|
||||
numeric arguments in process) after catching a signal, before calling
|
||||
rl_cleanup_after_signal(). */
|
||||
void
|
||||
rl_free_line_state ()
|
||||
{
|
||||
register HIST_ENTRY *entry;
|
||||
|
||||
rl_free_undo_list ();
|
||||
|
||||
entry = current_history ();
|
||||
if (entry)
|
||||
entry->data = (char *)NULL;
|
||||
|
||||
_rl_kill_kbd_macro ();
|
||||
rl_clear_message ();
|
||||
_rl_reset_argument ();
|
||||
}
|
||||
|
||||
#endif /* HANDLE_SIGNALS */
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* SIGINT Management */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
static sigset_t sigint_set, sigint_oset;
|
||||
static sigset_t sigwinch_set, sigwinch_oset;
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
# if defined (HAVE_BSD_SIGNALS)
|
||||
static int sigint_oldmask;
|
||||
static int sigwinch_oldmask;
|
||||
# endif /* HAVE_BSD_SIGNALS */
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
static int sigint_blocked;
|
||||
static int sigwinch_blocked;
|
||||
|
||||
/* Cause SIGINT to not be delivered until the corresponding call to
|
||||
release_sigint(). */
|
||||
void
|
||||
_rl_block_sigint ()
|
||||
{
|
||||
if (sigint_blocked)
|
||||
return;
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigemptyset (&sigint_set);
|
||||
sigemptyset (&sigint_oset);
|
||||
sigaddset (&sigint_set, SIGINT);
|
||||
sigprocmask (SIG_BLOCK, &sigint_set, &sigint_oset);
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
# if defined (HAVE_BSD_SIGNALS)
|
||||
sigint_oldmask = sigblock (sigmask (SIGINT));
|
||||
# else /* !HAVE_BSD_SIGNALS */
|
||||
# if defined (HAVE_USG_SIGHOLD)
|
||||
sighold (SIGINT);
|
||||
# endif /* HAVE_USG_SIGHOLD */
|
||||
# endif /* !HAVE_BSD_SIGNALS */
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
sigint_blocked = 1;
|
||||
}
|
||||
|
||||
/* Allow SIGINT to be delivered. */
|
||||
void
|
||||
_rl_release_sigint ()
|
||||
{
|
||||
if (sigint_blocked == 0)
|
||||
return;
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigprocmask (SIG_SETMASK, &sigint_oset, (sigset_t *)NULL);
|
||||
#else
|
||||
# if defined (HAVE_BSD_SIGNALS)
|
||||
sigsetmask (sigint_oldmask);
|
||||
# else /* !HAVE_BSD_SIGNALS */
|
||||
# if defined (HAVE_USG_SIGHOLD)
|
||||
sigrelse (SIGINT);
|
||||
# endif /* HAVE_USG_SIGHOLD */
|
||||
# endif /* !HAVE_BSD_SIGNALS */
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
sigint_blocked = 0;
|
||||
}
|
||||
|
||||
/* Cause SIGWINCH to not be delivered until the corresponding call to
|
||||
release_sigwinch(). */
|
||||
void
|
||||
_rl_block_sigwinch ()
|
||||
{
|
||||
if (sigwinch_blocked)
|
||||
return;
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigemptyset (&sigwinch_set);
|
||||
sigemptyset (&sigwinch_oset);
|
||||
sigaddset (&sigwinch_set, SIGWINCH);
|
||||
sigprocmask (SIG_BLOCK, &sigwinch_set, &sigwinch_oset);
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
# if defined (HAVE_BSD_SIGNALS)
|
||||
sigwinch_oldmask = sigblock (sigmask (SIGWINCH));
|
||||
# else /* !HAVE_BSD_SIGNALS */
|
||||
# if defined (HAVE_USG_SIGHOLD)
|
||||
sighold (SIGWINCH);
|
||||
# endif /* HAVE_USG_SIGHOLD */
|
||||
# endif /* !HAVE_BSD_SIGNALS */
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
sigwinch_blocked = 1;
|
||||
}
|
||||
|
||||
/* Allow SIGWINCH to be delivered. */
|
||||
void
|
||||
_rl_release_sigwinch ()
|
||||
{
|
||||
if (sigwinch_blocked == 0)
|
||||
return;
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigprocmask (SIG_SETMASK, &sigwinch_oset, (sigset_t *)NULL);
|
||||
#else
|
||||
# if defined (HAVE_BSD_SIGNALS)
|
||||
sigsetmask (sigwinch_oldmask);
|
||||
# else /* !HAVE_BSD_SIGNALS */
|
||||
# if defined (HAVE_USG_SIGHOLD)
|
||||
sigrelse (SIGWINCH);
|
||||
# endif /* HAVE_USG_SIGHOLD */
|
||||
# endif /* !HAVE_BSD_SIGNALS */
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
sigwinch_blocked = 0;
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Echoing special control characters */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
void
|
||||
rl_echo_signal_char (sig)
|
||||
int sig;
|
||||
{
|
||||
char cstr[3];
|
||||
int cslen, c;
|
||||
|
||||
if (_rl_echoctl == 0 || _rl_echo_control_chars == 0)
|
||||
return;
|
||||
|
||||
switch (sig)
|
||||
{
|
||||
case SIGINT: c = _rl_intr_char; break;
|
||||
#if defined (SIGQUIT)
|
||||
case SIGQUIT: c = _rl_quit_char; break;
|
||||
#endif
|
||||
#if defined (SIGTSTP)
|
||||
case SIGTSTP: c = _rl_susp_char; break;
|
||||
#endif
|
||||
default: return;
|
||||
}
|
||||
|
||||
if (CTRL_CHAR (c) || c == RUBOUT)
|
||||
{
|
||||
cstr[0] = '^';
|
||||
cstr[1] = CTRL_CHAR (c) ? UNCTRL (c) : '?';
|
||||
cstr[cslen = 2] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
cstr[0] = c;
|
||||
cstr[cslen = 1] = '\0';
|
||||
}
|
||||
|
||||
_rl_output_some_chars (cstr, cslen);
|
||||
}
|
||||
+11
-2
@@ -198,11 +198,20 @@ sh_eaccess (path, mode)
|
||||
char *path;
|
||||
int mode;
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (path_is_devfd (path))
|
||||
return (sh_stataccess (path, mode));
|
||||
|
||||
#if defined (HAVE_EACCESS) /* FreeBSD */
|
||||
return (eaccess (path, mode));
|
||||
#if defined (HAVE_FACCESSAT) && defined (AT_EACCESS)
|
||||
return (faccessat (AT_FDCWD, path, mode, AT_EACCESS));
|
||||
#elif defined (HAVE_EACCESS) /* FreeBSD */
|
||||
ret = eaccess (path, mode); /* XXX -- not always correct for X_OK */
|
||||
# if defined (__FreeBSD__)
|
||||
if (ret == 0 && current_user.euid == 0 && mode == X_OK)
|
||||
return (sh_stataccess (path, mode));
|
||||
# endif
|
||||
return ret;
|
||||
#elif defined (EFF_ONLY_OK) /* SVR4(?), SVR4.2 */
|
||||
return access (path, mode|EFF_ONLY_OK);
|
||||
#else
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
/* eaccess.c - eaccess replacement for the shell, plus other access functions. */
|
||||
|
||||
/* Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#include <errno.h>
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
#if !defined (_POSIX_VERSION) && defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif /* !_POSIX_VERSION */
|
||||
#include "posixstat.h"
|
||||
#include "filecntl.h"
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
#if !defined (R_OK)
|
||||
#define R_OK 4
|
||||
#define W_OK 2
|
||||
#define X_OK 1
|
||||
#define F_OK 0
|
||||
#endif /* R_OK */
|
||||
|
||||
static int path_is_devfd __P((const char *));
|
||||
static int sh_stataccess __P((char *, int));
|
||||
#if HAVE_DECL_SETREGID
|
||||
static int sh_euidaccess __P((char *, int));
|
||||
#endif
|
||||
|
||||
static int
|
||||
path_is_devfd (path)
|
||||
const char *path;
|
||||
{
|
||||
if (path[0] == '/' && path[1] == 'd' && strncmp (path, "/dev/fd/", 8) == 0)
|
||||
return 1;
|
||||
else if (STREQN (path, "/dev/std", 8))
|
||||
{
|
||||
if (STREQ (path+8, "in") || STREQ (path+8, "out") || STREQ (path+8, "err"))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A wrapper for stat () which disallows pathnames that are empty strings
|
||||
and handles /dev/fd emulation on systems that don't have it. */
|
||||
int
|
||||
sh_stat (path, finfo)
|
||||
const char *path;
|
||||
struct stat *finfo;
|
||||
{
|
||||
if (*path == '\0')
|
||||
{
|
||||
errno = ENOENT;
|
||||
return (-1);
|
||||
}
|
||||
if (path[0] == '/' && path[1] == 'd' && strncmp (path, "/dev/fd/", 8) == 0)
|
||||
{
|
||||
#if !defined (HAVE_DEV_FD)
|
||||
intmax_t fd;
|
||||
int r;
|
||||
|
||||
if (legal_number (path + 8, &fd) && fd == (int)fd)
|
||||
{
|
||||
r = fstat ((int)fd, finfo);
|
||||
if (r == 0 || errno != EBADF)
|
||||
return (r);
|
||||
}
|
||||
errno = ENOENT;
|
||||
return (-1);
|
||||
#else
|
||||
/* If HAVE_DEV_FD is defined, DEV_FD_PREFIX is defined also, and has a
|
||||
trailing slash. Make sure /dev/fd/xx really uses DEV_FD_PREFIX/xx.
|
||||
On most systems, with the notable exception of linux, this is
|
||||
effectively a no-op. */
|
||||
char pbuf[32];
|
||||
strcpy (pbuf, DEV_FD_PREFIX);
|
||||
strcat (pbuf, path + 8);
|
||||
return (stat (pbuf, finfo));
|
||||
#endif /* !HAVE_DEV_FD */
|
||||
}
|
||||
#if !defined (HAVE_DEV_STDIN)
|
||||
else if (STREQN (path, "/dev/std", 8))
|
||||
{
|
||||
if (STREQ (path+8, "in"))
|
||||
return (fstat (0, finfo));
|
||||
else if (STREQ (path+8, "out"))
|
||||
return (fstat (1, finfo));
|
||||
else if (STREQ (path+8, "err"))
|
||||
return (fstat (2, finfo));
|
||||
else
|
||||
return (stat (path, finfo));
|
||||
}
|
||||
#endif /* !HAVE_DEV_STDIN */
|
||||
return (stat (path, finfo));
|
||||
}
|
||||
|
||||
/* Do the same thing access(2) does, but use the effective uid and gid,
|
||||
and don't make the mistake of telling root that any file is
|
||||
executable. This version uses stat(2). */
|
||||
static int
|
||||
sh_stataccess (path, mode)
|
||||
char *path;
|
||||
int mode;
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (sh_stat (path, &st) < 0)
|
||||
return (-1);
|
||||
|
||||
if (current_user.euid == 0)
|
||||
{
|
||||
/* Root can read or write any file. */
|
||||
if ((mode & X_OK) == 0)
|
||||
return (0);
|
||||
|
||||
/* Root can execute any file that has any one of the execute
|
||||
bits set. */
|
||||
if (st.st_mode & S_IXUGO)
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (st.st_uid == current_user.euid) /* owner */
|
||||
mode <<= 6;
|
||||
else if (group_member (st.st_gid))
|
||||
mode <<= 3;
|
||||
|
||||
if (st.st_mode & mode)
|
||||
return (0);
|
||||
|
||||
errno = EACCES;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#if HAVE_DECL_SETREGID
|
||||
/* Version to call when uid != euid or gid != egid. We temporarily swap
|
||||
the effective and real uid and gid as appropriate. */
|
||||
static int
|
||||
sh_euidaccess (path, mode)
|
||||
char *path;
|
||||
int mode;
|
||||
{
|
||||
int r, e;
|
||||
|
||||
if (current_user.uid != current_user.euid)
|
||||
setreuid (current_user.euid, current_user.uid);
|
||||
if (current_user.gid != current_user.egid)
|
||||
setregid (current_user.egid, current_user.gid);
|
||||
|
||||
r = access (path, mode);
|
||||
e = errno;
|
||||
|
||||
if (current_user.uid != current_user.euid)
|
||||
setreuid (current_user.uid, current_user.euid);
|
||||
if (current_user.gid != current_user.egid)
|
||||
setregid (current_user.gid, current_user.egid);
|
||||
|
||||
errno = e;
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
sh_eaccess (path, mode)
|
||||
char *path;
|
||||
int mode;
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (path_is_devfd (path))
|
||||
return (sh_stataccess (path, mode));
|
||||
|
||||
#if defined (HAVE_FACCESSAT) && defined (AT_EACCESS)
|
||||
return (faccessat (AT_FDCWD, path, mode, AT_EACCESS));
|
||||
#elif defined (HAVE_EACCESS) /* FreeBSD */
|
||||
return (eaccess (path, mode)); /* XXX -- not always correct for X_OK */
|
||||
#elif defined (EFF_ONLY_OK) /* SVR4(?), SVR4.2 */
|
||||
return access (path, mode|EFF_ONLY_OK);
|
||||
#else
|
||||
if (mode == F_OK)
|
||||
return (sh_stataccess (path, mode));
|
||||
|
||||
# if HAVE_DECL_SETREGID
|
||||
if (current_user.uid != current_user.euid || current_user.gid != current_user.egid)
|
||||
return (sh_euidaccess (path, mode));
|
||||
# endif
|
||||
|
||||
if (current_user.uid == current_user.euid && current_user.gid == current_user.egid)
|
||||
return (access (path, mode));
|
||||
|
||||
return (sh_stataccess (path, mode));
|
||||
#endif
|
||||
}
|
||||
@@ -2305,7 +2305,7 @@ shell_getc (remove_quoted_newline)
|
||||
else
|
||||
{
|
||||
char *hdcs;
|
||||
hdcs = history_delimiting_chars ();
|
||||
hdcs = history_delimiting_chars (shell_input_line);
|
||||
if (hdcs && hdcs[0] == ';')
|
||||
maybe_add_history (shell_input_line);
|
||||
}
|
||||
@@ -3062,12 +3062,13 @@ tokword:
|
||||
* reprompting the user, if necessary, after reading a newline, and returning
|
||||
* correct error values if it reads EOF.
|
||||
*/
|
||||
#define P_FIRSTCLOSE 0x01
|
||||
#define P_ALLOWESC 0x02
|
||||
#define P_DQUOTE 0x04
|
||||
#define P_COMMAND 0x08 /* parsing a command, so look for comments */
|
||||
#define P_BACKQUOTE 0x10 /* parsing a backquoted command substitution */
|
||||
#define P_ARRAYSUB 0x20 /* parsing a [...] array subscript for assignment */
|
||||
#define P_FIRSTCLOSE 0x0001
|
||||
#define P_ALLOWESC 0x0002
|
||||
#define P_DQUOTE 0x0004
|
||||
#define P_COMMAND 0x0008 /* parsing a command, so look for comments */
|
||||
#define P_BACKQUOTE 0x0010 /* parsing a backquoted command substitution */
|
||||
#define P_ARRAYSUB 0x0020 /* parsing a [...] array subscript for assignment */
|
||||
#define P_DOLBRACE 0x0040 /* parsing a ${...} construct */
|
||||
|
||||
/* Lexical state while parsing a grouping construct or $(...). */
|
||||
#define LEX_WASDOL 0x001
|
||||
@@ -3115,6 +3116,9 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
||||
int nestlen, ttranslen, start_lineno;
|
||||
char *ret, *nestret, *ttrans;
|
||||
int retind, retsize, rflags;
|
||||
int dolbrace_state;
|
||||
|
||||
dolbrace_state = (flags & P_DOLBRACE) ? DOLBRACE_PARAM : 0;
|
||||
|
||||
/*itrace("parse_matched_pair[%d]: open = %c close = %c flags = %d", line_number, open, close, flags);*/
|
||||
count = 1;
|
||||
@@ -3225,12 +3229,33 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
||||
if MBTEST(ch == '\\') /* backslashes */
|
||||
tflags |= LEX_PASSNEXT;
|
||||
|
||||
#if 0
|
||||
#if 0 /* XXX - bash-4.2 */
|
||||
/* Based on which dolstate is currently in (param, op, or word),
|
||||
decide what the op is. We're really only concerned if it's % or
|
||||
#, so we can turn on a flag that says whether or not we should
|
||||
treat single quotes as special when inside a double-quoted
|
||||
${...}. This logic must agree with subst.c:extract_dollar_brace_string
|
||||
since they share the same defines. */
|
||||
if (flags & P_DOLBRACE)
|
||||
{
|
||||
if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '%' && retind > 0)
|
||||
dolbrace_state = DOLBRACE_QUOTE;
|
||||
else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '#' && retind > 1)
|
||||
dolbrace_state = DOLBRACE_QUOTE;
|
||||
else if MBTEST(dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", ch) != 0)
|
||||
dolbrace_state = DOLBRACE_OP;
|
||||
else if MBTEST(dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", ch) == 0)
|
||||
dolbrace_state = DOLBRACE_WORD;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0 /* XXX - bash-4.2 */
|
||||
/* The big hammer. Single quotes aren't special in double quotes. The
|
||||
problem is that Posix says the single quotes are semi-special:
|
||||
problem is that Posix used to say the single quotes are semi-special:
|
||||
within a double-quoted ${...} construct "an even number of
|
||||
unescaped double-quotes or single-quotes, if any, shall occur." */
|
||||
if MBTEST(open == '{' && (flags & P_DQUOTE) && ch == '\'') /* } */
|
||||
/* This was changed in Interp 221 */
|
||||
if MBTEST(/*posixly_correct && shell_compatibility_level > 41 &&*/ dolbrace_state == DOLBRACE_QUOTE && (flags & P_DQUOTE) && (flags & P_DOLBRACE) && ch == '\'')
|
||||
continue;
|
||||
#endif
|
||||
|
||||
@@ -3307,7 +3332,7 @@ parse_dollar_word:
|
||||
if (ch == '(') /* ) */
|
||||
nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE);
|
||||
else if (ch == '{') /* } */
|
||||
nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags);
|
||||
nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|P_DOLBRACE|rflags);
|
||||
else if (ch == '[') /* ] */
|
||||
nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags);
|
||||
|
||||
@@ -3750,7 +3775,7 @@ eof_error:
|
||||
if (ch == '(') /* ) */
|
||||
nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE);
|
||||
else if (ch == '{') /* } */
|
||||
nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags);
|
||||
nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|P_DOLBRACE|rflags);
|
||||
else if (ch == '[') /* ] */
|
||||
nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags);
|
||||
|
||||
@@ -4398,7 +4423,7 @@ read_token_word (character)
|
||||
((peek_char == '{' || peek_char == '[') && character == '$')) /* ) ] } */
|
||||
{
|
||||
if (peek_char == '{') /* } */
|
||||
ttok = parse_matched_pair (cd, '{', '}', &ttoklen, P_FIRSTCLOSE);
|
||||
ttok = parse_matched_pair (cd, '{', '}', &ttoklen, P_FIRSTCLOSE|P_DOLBRACE);
|
||||
else if (peek_char == '(') /* ) */
|
||||
{
|
||||
/* XXX - push and pop the `(' as a delimiter for use by
|
||||
@@ -4803,28 +4828,35 @@ static const int no_semi_successors[] = {
|
||||
/* If we are not within a delimited expression, try to be smart
|
||||
about which separators can be semi-colons and which must be
|
||||
newlines. Returns the string that should be added into the
|
||||
history entry. */
|
||||
history entry. LINE is the line we're about to add; it helps
|
||||
make some more intelligent decisions in certain cases. */
|
||||
char *
|
||||
history_delimiting_chars ()
|
||||
history_delimiting_chars (line)
|
||||
const char *line;
|
||||
{
|
||||
static int last_was_heredoc = 0; /* was the last entry the start of a here document? */
|
||||
register int i;
|
||||
|
||||
if ((parser_state & PST_HEREDOC) == 0)
|
||||
last_was_heredoc = 0;
|
||||
|
||||
if (dstack.delimiter_depth != 0)
|
||||
return ("\n");
|
||||
|
||||
/* We look for current_command_line_count == 2 because we are looking to
|
||||
add the first line of the body of the here document (the second line
|
||||
of the command). */
|
||||
of the command). We also keep LAST_WAS_HEREDOC as a private sentinel
|
||||
variable to note when we think we added the first line of a here doc
|
||||
(the one with a "<<" somewhere in it) */
|
||||
if (parser_state & PST_HEREDOC)
|
||||
#if 0
|
||||
{
|
||||
if (last_read_token == WORD && (token_before_that == LESS_LESS || token_before_that == LESS_LESS_MINUS))
|
||||
return ("\n"); /* XXX -- need to clean up in bash_add_history */
|
||||
#endif
|
||||
return (current_command_line_count == 2 ? "\n" : "");
|
||||
#if 0
|
||||
}
|
||||
#endif
|
||||
{
|
||||
if (last_was_heredoc)
|
||||
{
|
||||
last_was_heredoc = 0;
|
||||
return "\n";
|
||||
}
|
||||
return (current_command_line_count == 2 ? "\n" : "");
|
||||
}
|
||||
|
||||
/* First, handle some special cases. */
|
||||
/*(*/
|
||||
@@ -4847,6 +4879,15 @@ history_delimiting_chars ()
|
||||
else if (token_before_that == WORD && two_tokens_ago == FUNCTION)
|
||||
return " "; /* function def using `function name' without `()' */
|
||||
|
||||
/* If we're not in a here document, but we think we're about to parse one,
|
||||
and we would otherwise return a `;', return a newline to delimit the
|
||||
line with the here-doc delimiter */
|
||||
else if ((parser_state & PST_HEREDOC) == 0 && current_command_line_count > 1 && last_read_token == '\n' && strstr (line, "<<"))
|
||||
{
|
||||
last_was_heredoc = 1;
|
||||
return "\n";
|
||||
}
|
||||
|
||||
else if (token_before_that == WORD && two_tokens_ago == FOR)
|
||||
{
|
||||
/* Tricky. `for i\nin ...' should not have a semicolon, but
|
||||
|
||||
+5915
File diff suppressed because it is too large
Load Diff
@@ -2305,7 +2305,7 @@ shell_getc (remove_quoted_newline)
|
||||
else
|
||||
{
|
||||
char *hdcs;
|
||||
hdcs = history_delimiting_chars ();
|
||||
hdcs = history_delimiting_chars (shell_input_line);
|
||||
if (hdcs && hdcs[0] == ';')
|
||||
maybe_add_history (shell_input_line);
|
||||
}
|
||||
@@ -3062,12 +3062,13 @@ tokword:
|
||||
* reprompting the user, if necessary, after reading a newline, and returning
|
||||
* correct error values if it reads EOF.
|
||||
*/
|
||||
#define P_FIRSTCLOSE 0x01
|
||||
#define P_ALLOWESC 0x02
|
||||
#define P_DQUOTE 0x04
|
||||
#define P_COMMAND 0x08 /* parsing a command, so look for comments */
|
||||
#define P_BACKQUOTE 0x10 /* parsing a backquoted command substitution */
|
||||
#define P_ARRAYSUB 0x20 /* parsing a [...] array subscript for assignment */
|
||||
#define P_FIRSTCLOSE 0x0001
|
||||
#define P_ALLOWESC 0x0002
|
||||
#define P_DQUOTE 0x0004
|
||||
#define P_COMMAND 0x0008 /* parsing a command, so look for comments */
|
||||
#define P_BACKQUOTE 0x0010 /* parsing a backquoted command substitution */
|
||||
#define P_ARRAYSUB 0x0020 /* parsing a [...] array subscript for assignment */
|
||||
#define P_DOLBRACE 0x0040 /* parsing a ${...} construct */
|
||||
|
||||
/* Lexical state while parsing a grouping construct or $(...). */
|
||||
#define LEX_WASDOL 0x001
|
||||
@@ -3115,6 +3116,9 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
||||
int nestlen, ttranslen, start_lineno;
|
||||
char *ret, *nestret, *ttrans;
|
||||
int retind, retsize, rflags;
|
||||
int dolbrace_state;
|
||||
|
||||
dolbrace_state = (flags & P_DOLBRACE) ? DOLBRACE_PARAM : 0;
|
||||
|
||||
/*itrace("parse_matched_pair[%d]: open = %c close = %c flags = %d", line_number, open, close, flags);*/
|
||||
count = 1;
|
||||
@@ -3225,12 +3229,32 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
||||
if MBTEST(ch == '\\') /* backslashes */
|
||||
tflags |= LEX_PASSNEXT;
|
||||
|
||||
#if 0
|
||||
#if 0 /* XXX - bash-4.2 */
|
||||
/* Based on which dolstate is currently in (param, op, or word),
|
||||
decide what the op is. We're really only concerned if it's % or
|
||||
#, so we can turn on a flag that says whether or not we should
|
||||
treat single quotes as special when inside a double-quoted
|
||||
${...} */
|
||||
if (flags & P_DOLBRACE)
|
||||
{
|
||||
if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '%' && retind > 0)
|
||||
dolbrace_state = DOLBRACE_QUOTE;
|
||||
else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '#' && retind > 1)
|
||||
dolbrace_state = DOLBRACE_QUOTE;
|
||||
else if MBTEST(dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", ch) != 0)
|
||||
dolbrace_state = DOLBRACE_OP;
|
||||
else if MBTEST(dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", ch) == 0)
|
||||
dolbrace_state = DOLBRACE_WORD;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0 /* XXX - bash-4.2 */
|
||||
/* The big hammer. Single quotes aren't special in double quotes. The
|
||||
problem is that Posix says the single quotes are semi-special:
|
||||
problem is that Posix used to say the single quotes are semi-special:
|
||||
within a double-quoted ${...} construct "an even number of
|
||||
unescaped double-quotes or single-quotes, if any, shall occur." */
|
||||
if MBTEST(open == '{' && (flags & P_DQUOTE) && ch == '\'') /* } */
|
||||
/* This was changed in Interp 221 */
|
||||
if MBTEST(/*posixly_correct && shell_compatibility_level > 41 &&*/ dolbrace_state == DOLBRACE_QUOTE && (flags & P_DQUOTE) && (flags & P_DOLBRACE) && ch == '\'')
|
||||
continue;
|
||||
#endif
|
||||
|
||||
@@ -3307,7 +3331,7 @@ parse_dollar_word:
|
||||
if (ch == '(') /* ) */
|
||||
nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE);
|
||||
else if (ch == '{') /* } */
|
||||
nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags);
|
||||
nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|P_DOLBRACE|rflags);
|
||||
else if (ch == '[') /* ] */
|
||||
nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags);
|
||||
|
||||
@@ -3750,7 +3774,7 @@ eof_error:
|
||||
if (ch == '(') /* ) */
|
||||
nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE);
|
||||
else if (ch == '{') /* } */
|
||||
nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags);
|
||||
nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|P_DOLBRACE|rflags);
|
||||
else if (ch == '[') /* ] */
|
||||
nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags);
|
||||
|
||||
@@ -4398,7 +4422,7 @@ read_token_word (character)
|
||||
((peek_char == '{' || peek_char == '[') && character == '$')) /* ) ] } */
|
||||
{
|
||||
if (peek_char == '{') /* } */
|
||||
ttok = parse_matched_pair (cd, '{', '}', &ttoklen, P_FIRSTCLOSE);
|
||||
ttok = parse_matched_pair (cd, '{', '}', &ttoklen, P_FIRSTCLOSE|P_DOLBRACE);
|
||||
else if (peek_char == '(') /* ) */
|
||||
{
|
||||
/* XXX - push and pop the `(' as a delimiter for use by
|
||||
@@ -4803,24 +4827,35 @@ static const int no_semi_successors[] = {
|
||||
/* If we are not within a delimited expression, try to be smart
|
||||
about which separators can be semi-colons and which must be
|
||||
newlines. Returns the string that should be added into the
|
||||
history entry. */
|
||||
history entry. LINE is the line we're about to add; it helps
|
||||
make some more intelligent decisions in certain cases. */
|
||||
char *
|
||||
history_delimiting_chars ()
|
||||
history_delimiting_chars (line)
|
||||
const char *line;
|
||||
{
|
||||
static int last_was_heredoc = 0; /* was the last entry the start of a here document? */
|
||||
register int i;
|
||||
|
||||
if ((parser_state & PST_HEREDOC) == 0)
|
||||
last_was_heredoc = 0;
|
||||
|
||||
if (dstack.delimiter_depth != 0)
|
||||
return ("\n");
|
||||
|
||||
/* We look for current_command_line_count == 2 because we are looking to
|
||||
add the first line of the body of the here document (the second line
|
||||
of the command). */
|
||||
of the command). We also keep LAST_WAS_HEREDOC as a private sentinel
|
||||
variable to note when we think we added the first line of a here doc
|
||||
(the one with a "<<" somewhere in it) */
|
||||
if (parser_state & PST_HEREDOC)
|
||||
{
|
||||
if (last_read_token == WORD && (token_before_that == LESS_LESS || token_before_that == LESS_LESS_MINUS))
|
||||
return ("\n"); /* XXX -- need to clean up in bash_add_history */
|
||||
return (current_command_line_count == 2 ? "\n" : "");
|
||||
}
|
||||
{
|
||||
if (last_was_heredoc)
|
||||
{
|
||||
last_was_heredoc = 0;
|
||||
return "\n";
|
||||
}
|
||||
return (current_command_line_count == 2 ? "\n" : "");
|
||||
}
|
||||
|
||||
/* First, handle some special cases. */
|
||||
/*(*/
|
||||
@@ -4843,6 +4878,15 @@ history_delimiting_chars ()
|
||||
else if (token_before_that == WORD && two_tokens_ago == FUNCTION)
|
||||
return " "; /* function def using `function name' without `()' */
|
||||
|
||||
/* If we're not in a here document, but we think we're about to parse one,
|
||||
and we would otherwise return a `;', return a newline to delimit the
|
||||
line with the here-doc delimiter */
|
||||
else if ((parser_state & PST_HEREDOC) == 0 && current_command_line_count > 1 && last_read_token == '\n' && strstr (line, "<<"))
|
||||
{
|
||||
last_was_heredoc = 1;
|
||||
return "\n";
|
||||
}
|
||||
|
||||
else if (token_before_that == WORD && two_tokens_ago == FOR)
|
||||
{
|
||||
/* Tricky. `for i\nin ...' should not have a semicolon, but
|
||||
|
||||
@@ -61,4 +61,12 @@ struct dstack {
|
||||
int delimiter_space;
|
||||
};
|
||||
|
||||
/* States we can be in while scanning a ${...} expansion. Shared between
|
||||
parse.y and subst.c */
|
||||
#define DOLBRACE_PARAM 0x01
|
||||
#define DOLBRACE_OP 0x02
|
||||
#define DOLBRACE_WORD 0x04
|
||||
|
||||
#define DOLBRACE_QUOTE 0x40
|
||||
|
||||
#endif /* _PARSER_H_ */
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/* parser.h -- Everything you wanted to know about the parser, but were
|
||||
afraid to ask. */
|
||||
|
||||
/* Copyright (C) 1995, 2008,2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_PARSER_H_)
|
||||
# define _PARSER_H_
|
||||
|
||||
# include "command.h"
|
||||
# include "input.h"
|
||||
|
||||
/* Possible states for the parser that require it to do special things. */
|
||||
#define PST_CASEPAT 0x000001 /* in a case pattern list */
|
||||
#define PST_ALEXPNEXT 0x000002 /* expand next word for aliases */
|
||||
#define PST_ALLOWOPNBRC 0x000004 /* allow open brace for function def */
|
||||
#define PST_NEEDCLOSBRC 0x000008 /* need close brace */
|
||||
#define PST_DBLPAREN 0x000010 /* double-paren parsing */
|
||||
#define PST_SUBSHELL 0x000020 /* ( ... ) subshell */
|
||||
#define PST_CMDSUBST 0x000040 /* $( ... ) command substitution */
|
||||
#define PST_CASESTMT 0x000080 /* parsing a case statement */
|
||||
#define PST_CONDCMD 0x000100 /* parsing a [[...]] command */
|
||||
#define PST_CONDEXPR 0x000200 /* parsing the guts of [[...]] */
|
||||
#define PST_ARITHFOR 0x000400 /* parsing an arithmetic for command */
|
||||
#define PST_ALEXPAND 0x000800 /* OK to expand aliases - unused */
|
||||
#define PST_EXTPAT 0x001000 /* parsing an extended shell pattern */
|
||||
#define PST_COMPASSIGN 0x002000 /* parsing x=(...) compound assignment */
|
||||
#define PST_ASSIGNOK 0x004000 /* assignment statement ok in this context */
|
||||
#define PST_EOFTOKEN 0x008000 /* yylex checks against shell_eof_token */
|
||||
#define PST_REGEXP 0x010000 /* parsing an ERE/BRE as a single word */
|
||||
#define PST_HEREDOC 0x020000 /* reading body of here-document */
|
||||
#define PST_REPARSE 0x040000 /* re-parsing in parse_string_to_word_list */
|
||||
#define PST_REDIRLIST 0x080000 /* parsing a list of redirctions preceding a simple command name */
|
||||
|
||||
|
||||
/* Definition of the delimiter stack. Needed by parse.y and bashhist.c. */
|
||||
struct dstack {
|
||||
/* DELIMITERS is a stack of the nested delimiters that we have
|
||||
encountered so far. */
|
||||
char *delimiters;
|
||||
|
||||
/* Offset into the stack of delimiters. */
|
||||
int delimiter_depth;
|
||||
|
||||
/* How many slots are allocated to DELIMITERS. */
|
||||
int delimiter_space;
|
||||
};
|
||||
|
||||
#endif /* _PARSER_H_ */
|
||||
@@ -216,7 +216,8 @@ static int termsigs_initialized = 0;
|
||||
|
||||
/* Initialize signals that will terminate the shell to do some
|
||||
unwind protection. For non-interactive shells, we only call
|
||||
this when a trap is defined for EXIT (0). */
|
||||
this when a trap is defined for EXIT (0) or when trap is run
|
||||
to display signal dispositions. */
|
||||
void
|
||||
initialize_terminating_signals ()
|
||||
{
|
||||
@@ -250,7 +251,8 @@ initialize_terminating_signals ()
|
||||
XSAFLAGS(i) = oact.sa_flags;
|
||||
/* Don't do anything with signals that are ignored at shell entry
|
||||
if the shell is not interactive. */
|
||||
if (!interactive_shell && XHANDLER (i) == SIG_IGN)
|
||||
/* XXX - should we do this for interactive shells, too? */
|
||||
if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN)
|
||||
{
|
||||
sigaction (XSIG (i), &oact, &act);
|
||||
set_signal_ignored (XSIG (i));
|
||||
@@ -273,7 +275,8 @@ initialize_terminating_signals ()
|
||||
XSAFLAGS(i) = 0;
|
||||
/* Don't do anything with signals that are ignored at shell entry
|
||||
if the shell is not interactive. */
|
||||
if (!interactive_shell && XHANDLER (i) == SIG_IGN)
|
||||
/* XXX - should we do this for interactive shells, too? */
|
||||
if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN)
|
||||
{
|
||||
signal (XSIG (i), SIG_IGN);
|
||||
set_signal_ignored (XSIG (i));
|
||||
@@ -652,12 +655,13 @@ set_signal_handler (sig, handler)
|
||||
|
||||
act.sa_handler = handler;
|
||||
act.sa_flags = 0;
|
||||
#if 0
|
||||
if (sig == SIGALRM)
|
||||
act.sa_flags |= SA_INTERRUPT; /* XXX */
|
||||
else
|
||||
|
||||
/* XXX - bash-4.2 */
|
||||
/* We don't want a child death to interrupt interruptible system calls, even
|
||||
if we take the time to reap children */
|
||||
if (sig == SIGCHLD)
|
||||
act.sa_flags |= SA_RESTART; /* XXX */
|
||||
#endif
|
||||
|
||||
sigemptyset (&act.sa_mask);
|
||||
sigemptyset (&oact.sa_mask);
|
||||
sigaction (sig, &act, &oact);
|
||||
|
||||
@@ -60,6 +60,8 @@ extern int executing_list;
|
||||
extern int comsub_ignore_return;
|
||||
extern int parse_and_execute_level, shell_initialized;
|
||||
|
||||
extern void intialize_siglist ();
|
||||
|
||||
/* Non-zero after SIGINT. */
|
||||
volatile int interrupt_state = 0;
|
||||
|
||||
@@ -214,7 +216,8 @@ static int termsigs_initialized = 0;
|
||||
|
||||
/* Initialize signals that will terminate the shell to do some
|
||||
unwind protection. For non-interactive shells, we only call
|
||||
this when a trap is defined for EXIT (0). */
|
||||
this when a trap is defined for EXIT (0) or when trap is run
|
||||
to display signal dispositions. */
|
||||
void
|
||||
initialize_terminating_signals ()
|
||||
{
|
||||
@@ -248,7 +251,8 @@ initialize_terminating_signals ()
|
||||
XSAFLAGS(i) = oact.sa_flags;
|
||||
/* Don't do anything with signals that are ignored at shell entry
|
||||
if the shell is not interactive. */
|
||||
if (!interactive_shell && XHANDLER (i) == SIG_IGN)
|
||||
/* XXX - should we do this for interactive shells, too? */
|
||||
if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN)
|
||||
{
|
||||
sigaction (XSIG (i), &oact, &act);
|
||||
set_signal_ignored (XSIG (i));
|
||||
@@ -271,7 +275,8 @@ initialize_terminating_signals ()
|
||||
XSAFLAGS(i) = 0;
|
||||
/* Don't do anything with signals that are ignored at shell entry
|
||||
if the shell is not interactive. */
|
||||
if (!interactive_shell && XHANDLER (i) == SIG_IGN)
|
||||
/* XXX - should we do this for interactive shells, too? */
|
||||
if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN)
|
||||
{
|
||||
signal (XSIG (i), SIG_IGN);
|
||||
set_signal_ignored (XSIG (i));
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "parser.h"
|
||||
#include "flags.h"
|
||||
#include "jobs.h"
|
||||
#include "execute_cmd.h"
|
||||
@@ -785,6 +786,7 @@ string_extract_double_quoted (string, sindex, stripdq)
|
||||
/* Process a character that was quoted by a backslash. */
|
||||
if (pass_next)
|
||||
{
|
||||
/* XXX - take another look at this in light of Interp 221 */
|
||||
/* Posix.2 sez:
|
||||
|
||||
``The backslash shall retain its special meaning as an escape
|
||||
@@ -960,7 +962,7 @@ skip_double_quoted (string, slen, sind)
|
||||
if (string[i + 1] == LPAREN)
|
||||
ret = extract_command_subst (string, &si, SX_NOALLOC);
|
||||
else
|
||||
ret = extract_dollar_brace_string (string, &si, 1, SX_NOALLOC);
|
||||
ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC);
|
||||
|
||||
i = si + 1;
|
||||
continue;
|
||||
@@ -1266,7 +1268,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
|
||||
|
||||
#if 0
|
||||
/* Process a nested command substitution, but only if we're parsing a
|
||||
command substitution. XXX - for bash-4.2 */
|
||||
command substitution. XXX - bash-4.2 */
|
||||
if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN)
|
||||
{
|
||||
si = i + 2;
|
||||
@@ -1370,7 +1372,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
|
||||
{
|
||||
register int i, c;
|
||||
size_t slen;
|
||||
int pass_character, nesting_level, si;
|
||||
int pass_character, nesting_level, si, dolbrace_state;
|
||||
char *result, *t;
|
||||
DECLARE_MBSTATE;
|
||||
|
||||
@@ -1378,6 +1380,12 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
|
||||
nesting_level = 1;
|
||||
slen = strlen (string + *sindex) + *sindex;
|
||||
|
||||
/* The handling of dolbrace_state needs to agree with the code in parse.y:
|
||||
parse_matched_pair() */
|
||||
dolbrace_state = 0;
|
||||
if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
|
||||
dolbrace_state = (flags & SX_POSIXEXP) ? DOLBRACE_QUOTE : DOLBRACE_PARAM;
|
||||
|
||||
i = *sindex;
|
||||
while (c = string[i])
|
||||
{
|
||||
@@ -1432,6 +1440,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
|
||||
continue;
|
||||
}
|
||||
|
||||
#if 1
|
||||
/* Pass the contents of single-quoted and double-quoted strings
|
||||
through verbatim. */
|
||||
if (c == '\'' || c == '"')
|
||||
@@ -1442,9 +1451,44 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
|
||||
/* skip_XXX_quoted leaves index one past close quote */
|
||||
continue;
|
||||
}
|
||||
#else /* XXX - bash-4.2 */
|
||||
/* Pass the contents of double-quoted strings through verbatim. */
|
||||
if (c == '"')
|
||||
{
|
||||
si = i + 1;
|
||||
i = skip_double_quoted (string, slen, si);
|
||||
/* skip_XXX_quoted leaves index one past close quote */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\'')
|
||||
{
|
||||
/*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/
|
||||
if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE)
|
||||
ADVANCE_CHAR (string, slen, i);
|
||||
else
|
||||
{
|
||||
si = i + 1;
|
||||
i = skip_single_quoted (string, slen, si);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* move past this character, which was not special. */
|
||||
ADVANCE_CHAR (string, slen, i);
|
||||
|
||||
/* This logic must agree with parse.y:parse_matched_pair, since they
|
||||
share the same defines. */
|
||||
if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 0)
|
||||
dolbrace_state = DOLBRACE_QUOTE;
|
||||
else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1)
|
||||
dolbrace_state = DOLBRACE_QUOTE;
|
||||
else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0)
|
||||
dolbrace_state = DOLBRACE_OP;
|
||||
else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0)
|
||||
dolbrace_state = DOLBRACE_WORD;
|
||||
}
|
||||
|
||||
if (c == 0 && nesting_level)
|
||||
@@ -5596,7 +5640,7 @@ parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat)
|
||||
|
||||
w->word = temp;
|
||||
#else /* XXX - bash-4.2 */
|
||||
/* From Posix group discussion Feb-March 2010 */
|
||||
/* From Posix group discussion Feb-March 2010. Issue 7 0000221 */
|
||||
free (temp);
|
||||
|
||||
w->word = t1;
|
||||
@@ -6895,7 +6939,7 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
{
|
||||
/* Extract the contents of the ${ ... } expansion
|
||||
according to the Posix.2 rules. */
|
||||
value = extract_dollar_brace_string (string, &sindex, quoted, 0);
|
||||
value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#') ? SX_POSIXEXP : 0);
|
||||
if (string[sindex] == RBRACE)
|
||||
sindex++;
|
||||
else
|
||||
@@ -7015,7 +7059,6 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
{
|
||||
/* If the operator is `+', we don't want the value of the named
|
||||
variable for anything, just the value of the right hand side. */
|
||||
|
||||
if (c == '+')
|
||||
{
|
||||
/* XXX -- if we're double-quoted and the named variable is "$@",
|
||||
@@ -7030,7 +7073,7 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
if (value)
|
||||
{
|
||||
/* XXX - bash-4.2 */
|
||||
/* From Posix discussion on austin-group list */
|
||||
/* From Posix discussion on austin-group list. Issue 221 */
|
||||
if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
|
||||
quoted |= Q_DOLBRACE;
|
||||
ret = parameter_brace_expand_rhs (name, value, c,
|
||||
@@ -7076,6 +7119,8 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
if (contains_dollar_at)
|
||||
*contains_dollar_at = 0;
|
||||
|
||||
/* XXX - bash-4.2 */
|
||||
/* From Posix discussion on austin-group list. Issue 221 */
|
||||
if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
|
||||
quoted |= Q_DOLBRACE;
|
||||
ret = parameter_brace_expand_rhs (name, value, c, quoted,
|
||||
@@ -7894,9 +7939,10 @@ add_string:
|
||||
else
|
||||
tflag = 0;
|
||||
|
||||
/* XXX - bash-4.2 */
|
||||
/* From Posix discussion on austin-group list: Backslash escaping
|
||||
{ or } in ${...} is removed. */
|
||||
if ((quoted & Q_DOLBRACE) && (c == '{' || c == '}'))
|
||||
a } in ${...} is removed. Issue 0000221 */
|
||||
if ((quoted & Q_DOLBRACE) && c == RBRACE)
|
||||
{
|
||||
SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "parser.h"
|
||||
#include "flags.h"
|
||||
#include "jobs.h"
|
||||
#include "execute_cmd.h"
|
||||
@@ -785,6 +786,7 @@ string_extract_double_quoted (string, sindex, stripdq)
|
||||
/* Process a character that was quoted by a backslash. */
|
||||
if (pass_next)
|
||||
{
|
||||
/* XXX - take another look at this in light of Interp 221 */
|
||||
/* Posix.2 sez:
|
||||
|
||||
``The backslash shall retain its special meaning as an escape
|
||||
@@ -960,7 +962,7 @@ skip_double_quoted (string, slen, sind)
|
||||
if (string[i + 1] == LPAREN)
|
||||
ret = extract_command_subst (string, &si, SX_NOALLOC);
|
||||
else
|
||||
ret = extract_dollar_brace_string (string, &si, 1, SX_NOALLOC);
|
||||
ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC);
|
||||
|
||||
i = si + 1;
|
||||
continue;
|
||||
@@ -1266,7 +1268,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
|
||||
|
||||
#if 0
|
||||
/* Process a nested command substitution, but only if we're parsing a
|
||||
command substitution. XXX - for bash-4.2 */
|
||||
command substitution. XXX - bash-4.2 */
|
||||
if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN)
|
||||
{
|
||||
si = i + 2;
|
||||
@@ -1370,7 +1372,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
|
||||
{
|
||||
register int i, c;
|
||||
size_t slen;
|
||||
int pass_character, nesting_level, si;
|
||||
int pass_character, nesting_level, si, dolbrace_state;
|
||||
char *result, *t;
|
||||
DECLARE_MBSTATE;
|
||||
|
||||
@@ -1378,6 +1380,12 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
|
||||
nesting_level = 1;
|
||||
slen = strlen (string + *sindex) + *sindex;
|
||||
|
||||
/* The handling of dolbrace_state needs to agree with the code in parse.y:
|
||||
parse_matched_pair() */
|
||||
dolbrace_state = 0;
|
||||
if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
|
||||
dolbrace_state = (flags & SX_POSIXEXP) ? DOLBRACE_QUOTE : DOLBRACE_PARAM;
|
||||
|
||||
i = *sindex;
|
||||
while (c = string[i])
|
||||
{
|
||||
@@ -1432,6 +1440,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
|
||||
continue;
|
||||
}
|
||||
|
||||
#if 1
|
||||
/* Pass the contents of single-quoted and double-quoted strings
|
||||
through verbatim. */
|
||||
if (c == '\'' || c == '"')
|
||||
@@ -1442,9 +1451,44 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
|
||||
/* skip_XXX_quoted leaves index one past close quote */
|
||||
continue;
|
||||
}
|
||||
#else /* XXX - bash-4.2 */
|
||||
/* Pass the contents of double-quoted strings through verbatim. */
|
||||
if (c == '"')
|
||||
{
|
||||
si = i + 1;
|
||||
i = skip_double_quoted (string, slen, si);
|
||||
/* skip_XXX_quoted leaves index one past close quote */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\'')
|
||||
{
|
||||
/*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/
|
||||
if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE)
|
||||
ADVANCE_CHAR (string, slen, i);
|
||||
else
|
||||
{
|
||||
si = i + 1;
|
||||
i = skip_single_quoted (string, slen, si);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* move past this character, which was not special. */
|
||||
ADVANCE_CHAR (string, slen, i);
|
||||
|
||||
/* This logic must agree with parse.y:parse_matched_pair, since they
|
||||
share the same defines. */
|
||||
if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 0)
|
||||
dolbrace_state = DOLBRACE_QUOTE;
|
||||
else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1)
|
||||
dolbrace_state = DOLBRACE_QUOTE;
|
||||
else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0)
|
||||
dolbrace_state = DOLBRACE_OP;
|
||||
else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0)
|
||||
dolbrace_state = DOLBRACE_WORD;
|
||||
}
|
||||
|
||||
if (c == 0 && nesting_level)
|
||||
@@ -5591,11 +5635,12 @@ parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat)
|
||||
else
|
||||
#endif /* ARRAY_VARS */
|
||||
bind_variable (name, t1, 0);
|
||||
#if 0
|
||||
#if 1
|
||||
free (t1);
|
||||
|
||||
w->word = temp;
|
||||
#else /* XXX - bash-4.2 -- depends on Posix group interpretation */
|
||||
#else /* XXX - bash-4.2 */
|
||||
/* From Posix group discussion Feb-March 2010. Issue 7 0000221 */
|
||||
free (temp);
|
||||
|
||||
w->word = t1;
|
||||
@@ -6894,7 +6939,7 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
{
|
||||
/* Extract the contents of the ${ ... } expansion
|
||||
according to the Posix.2 rules. */
|
||||
value = extract_dollar_brace_string (string, &sindex, quoted, 0);
|
||||
value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#') ? SX_POSIXEXP : 0);
|
||||
if (string[sindex] == RBRACE)
|
||||
sindex++;
|
||||
else
|
||||
@@ -7029,7 +7074,7 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
if (value)
|
||||
{
|
||||
/* XXX - bash-4.2 */
|
||||
/* From Posix discussion on austin-group list */
|
||||
/* From Posix discussion on austin-group list. Issue 221 */
|
||||
if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
|
||||
quoted |= Q_DOLBRACE;
|
||||
ret = parameter_brace_expand_rhs (name, value, c,
|
||||
@@ -7075,6 +7120,8 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
if (contains_dollar_at)
|
||||
*contains_dollar_at = 0;
|
||||
|
||||
/* XXX - bash-4.2 */
|
||||
/* From Posix discussion on austin-group list. Issue 221 */
|
||||
if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
|
||||
quoted |= Q_DOLBRACE;
|
||||
ret = parameter_brace_expand_rhs (name, value, c, quoted,
|
||||
@@ -7893,9 +7940,10 @@ add_string:
|
||||
else
|
||||
tflag = 0;
|
||||
|
||||
/* XXX - bash-4.2 */
|
||||
/* From Posix discussion on austin-group list: Backslash escaping
|
||||
{ or } in ${...} is removed. */
|
||||
if ((quoted & Q_DOLBRACE) && (c == '{' || c == '}'))
|
||||
a } in ${...} is removed. Issue 0000221 */
|
||||
if ((quoted & Q_DOLBRACE) && c == RBRACE)
|
||||
{
|
||||
SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
|
||||
}
|
||||
|
||||
@@ -47,14 +47,15 @@
|
||||
#define ASS_MKASSOC 0x04
|
||||
|
||||
/* Flags for the string extraction functions. */
|
||||
#define SX_NOALLOC 0x01 /* just skip; don't return substring */
|
||||
#define SX_VARNAME 0x02 /* variable name; for string_extract () */
|
||||
#define SX_REQMATCH 0x04 /* closing/matching delimiter required */
|
||||
#define SX_COMMAND 0x08 /* extracting a shell script/command */
|
||||
#define SX_NOCTLESC 0x10 /* don't honor CTLESC quoting */
|
||||
#define SX_NOESCCTLNUL 0x20 /* don't let CTLESC quote CTLNUL */
|
||||
#define SX_NOLONGJMP 0x40 /* don't longjmp on fatal error */
|
||||
#define SX_ARITHSUB 0x80 /* extracting $(( ... )) (currently unused) */
|
||||
#define SX_NOALLOC 0x0001 /* just skip; don't return substring */
|
||||
#define SX_VARNAME 0x0002 /* variable name; for string_extract () */
|
||||
#define SX_REQMATCH 0x0004 /* closing/matching delimiter required */
|
||||
#define SX_COMMAND 0x0008 /* extracting a shell script/command */
|
||||
#define SX_NOCTLESC 0x0010 /* don't honor CTLESC quoting */
|
||||
#define SX_NOESCCTLNUL 0x0020 /* don't let CTLESC quote CTLNUL */
|
||||
#define SX_NOLONGJMP 0x0040 /* don't longjmp on fatal error */
|
||||
#define SX_ARITHSUB 0x0080 /* extracting $(( ... )) (currently unused) */
|
||||
#define SX_POSIXEXP 0x0100 /* extracting new Posix pattern removal expansions in extract_dollar_brace_string */
|
||||
|
||||
/* Remove backslashes which are quoting backquotes from STRING. Modifies
|
||||
STRING, and returns a pointer to it. */
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
decide whether to retain the backslash. Q_KEEP_BACKSLASH means
|
||||
to unconditionally retain the backslash. Q_PATQUOTE means that we're
|
||||
expanding a pattern ${var%#[#%]pattern} in an expansion surrounded
|
||||
by double quotes. */
|
||||
by double quotes. Q_DOLBRACE means we are expanding a ${...} word, so
|
||||
backslashes should also escape { and } and be removed. */
|
||||
#define Q_DOUBLE_QUOTES 0x01
|
||||
#define Q_HERE_DOCUMENT 0x02
|
||||
#define Q_KEEP_BACKSLASH 0x04
|
||||
@@ -38,6 +39,7 @@
|
||||
#define Q_QUOTED 0x10
|
||||
#define Q_ADDEDQUOTES 0x20
|
||||
#define Q_QUOTEDNULL 0x40
|
||||
#define Q_DOLBRACE 0x80
|
||||
|
||||
/* Flag values controlling how assignment statements are treated. */
|
||||
#define ASS_APPEND 0x01
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
BUILD_DIR=/usr/local/build/bash/bash-current
|
||||
BUILD_DIR=/usr/local/build/chet/bash/bash-current
|
||||
THIS_SH=$BUILD_DIR/bash
|
||||
PATH=$PATH:$BUILD_DIR
|
||||
|
||||
|
||||
@@ -121,6 +121,13 @@ int wait_signal_received;
|
||||
sigmodes[sig] |= SIG_HARD_IGNORE; \
|
||||
} while (0)
|
||||
|
||||
#define SETORIGSIG(sig,handler) \
|
||||
do { \
|
||||
original_signals[sig] = handler; \
|
||||
if (original_signals[sig] == SIG_IGN) \
|
||||
sigmodes[sig] |= SIG_HARD_IGNORE; \
|
||||
} while (0)
|
||||
|
||||
#define GET_ORIGINAL_SIGNAL(sig) \
|
||||
if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
|
||||
GETORIGSIG(sig)
|
||||
@@ -140,7 +147,7 @@ initialize_traps ()
|
||||
{
|
||||
pending_traps[i] = 0;
|
||||
trap_list[i] = (char *)DEFAULT_SIG;
|
||||
sigmodes[i] = SIG_INHERITED;
|
||||
sigmodes[i] = SIG_INHERITED; /* XXX - only set, not used */
|
||||
original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
|
||||
}
|
||||
|
||||
@@ -600,6 +607,15 @@ get_original_signal (sig)
|
||||
GETORIGSIG (sig);
|
||||
}
|
||||
|
||||
void
|
||||
set_original_signal (sig, handler)
|
||||
int sig;
|
||||
SigHandler *handler;
|
||||
{
|
||||
if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
|
||||
SETORIGSIG (sig, handler);
|
||||
}
|
||||
|
||||
/* Restore the default action for SIG; i.e., the action the shell
|
||||
would have taken before you used the trap command. This is called
|
||||
from trap_builtin (), which takes care to restore the handlers for
|
||||
@@ -1071,6 +1087,12 @@ signal_is_ignored (sig)
|
||||
return (sigmodes[sig] & SIG_IGNORED);
|
||||
}
|
||||
|
||||
int
|
||||
signal_is_hard_ignored (sig)
|
||||
{
|
||||
return (sigmodes[sig] & SIG_HARD_IGNORE);
|
||||
}
|
||||
|
||||
void
|
||||
set_signal_ignored (sig)
|
||||
int sig;
|
||||
|
||||
@@ -121,6 +121,13 @@ int wait_signal_received;
|
||||
sigmodes[sig] |= SIG_HARD_IGNORE; \
|
||||
} while (0)
|
||||
|
||||
#define SETORIGSIG(sig,handler) \
|
||||
do { \
|
||||
original_signals[sig] = handler; \
|
||||
if (original_signals[sig] == SIG_IGN) \
|
||||
sigmodes[sig] |= SIG_HARD_IGNORE; \
|
||||
} while (0)
|
||||
|
||||
#define GET_ORIGINAL_SIGNAL(sig) \
|
||||
if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
|
||||
GETORIGSIG(sig)
|
||||
@@ -140,7 +147,7 @@ initialize_traps ()
|
||||
{
|
||||
pending_traps[i] = 0;
|
||||
trap_list[i] = (char *)DEFAULT_SIG;
|
||||
sigmodes[i] = SIG_INHERITED;
|
||||
sigmodes[i] = SIG_INHERITED; /* XXX - only set, not used */
|
||||
original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
|
||||
}
|
||||
|
||||
@@ -600,6 +607,15 @@ get_original_signal (sig)
|
||||
GETORIGSIG (sig);
|
||||
}
|
||||
|
||||
void
|
||||
set_original_signal (sig, handler)
|
||||
int sig;
|
||||
SigHandler *handler;
|
||||
{
|
||||
if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
|
||||
SETORIGSIG (sig, handler);
|
||||
}
|
||||
|
||||
/* Restore the default action for SIG; i.e., the action the shell
|
||||
would have taken before you used the trap command. This is called
|
||||
from trap_builtin (), which takes care to restore the handlers for
|
||||
@@ -912,7 +928,6 @@ run_interrupt_trap ()
|
||||
_run_trap_internal (SIGINT, "interrupt trap");
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* Free all the allocated strings in the list of traps and reset the trap
|
||||
values to the default. Intended to be called from subshells that want
|
||||
to complete work done by reset_signal_handlers upon execution of a
|
||||
@@ -936,7 +951,6 @@ free_trap_string (sig)
|
||||
change_signal (sig, (char *)DEFAULT_SIG);
|
||||
sigmodes[sig] &= ~SIG_TRAPPED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Reset the handler for SIG to the original value. */
|
||||
static void
|
||||
@@ -1073,10 +1087,17 @@ signal_is_ignored (sig)
|
||||
return (sigmodes[sig] & SIG_IGNORED);
|
||||
}
|
||||
|
||||
int
|
||||
signal_is_hard_ignored (sig)
|
||||
{
|
||||
return (sigmodes[sig] & SIG_HARD_IGNORE);
|
||||
}
|
||||
|
||||
void
|
||||
set_signal_ignored (sig)
|
||||
int sig;
|
||||
{
|
||||
itrace("set_signal_ignored: %d set to SIG_HARD_IGNORE", sig);
|
||||
sigmodes[sig] |= SIG_HARD_IGNORE;
|
||||
original_signals[sig] = SIG_IGN;
|
||||
}
|
||||
|
||||
@@ -93,9 +93,10 @@ extern char *signal_name __P((int));
|
||||
extern int decode_signal __P((char *, int));
|
||||
extern void run_interrupt_trap __P((void));
|
||||
extern int maybe_call_trap_handler __P((int));
|
||||
extern int signal_is_special __P((int));
|
||||
extern int signal_is_trapped __P((int));
|
||||
extern int signal_is_ignored __P((int));
|
||||
extern int signal_is_special __P((int));
|
||||
extern int signal_is_hard_ignored __P((int));
|
||||
extern void set_signal_ignored __P((int));
|
||||
extern int signal_in_progress __P((int));
|
||||
|
||||
|
||||
@@ -49,6 +49,9 @@
|
||||
#define DSIG_SIGPREFIX 0x01 /* don't alllow `SIG' PREFIX */
|
||||
#define DSIG_NOCASE 0x02 /* case-insensitive comparison */
|
||||
|
||||
/* A value which can never be the target of a trap handler. */
|
||||
#define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps
|
||||
|
||||
#define signal_object_p(x,f) (decode_signal (x,f) != NO_SIG)
|
||||
|
||||
#define TRAP_STRING(s) \
|
||||
|
||||
Reference in New Issue
Block a user