commit bash-20110525 snapshot

This commit is contained in:
Chet Ramey
2011-12-29 13:08:48 -05:00
parent 22818c1449
commit 276cb932b6
35 changed files with 14195 additions and 159 deletions
+90
View File
@@ -11734,3 +11734,93 @@ expr.c
bind_variable and check whether or not we should error out due to
a readonly or noassign variable. Fixes bug reported by Eric
Blake <eblake@redhat.com>
5/26
----
lib/readline/search.c
- include histlib.h for ANCHORED_SEARCH defines
- rl_history_search_flags: new variable, holds ANCHORED_SEARCH flag for
the duration of a history search
- rl_history_search_reinit: takes a new flags variable, defines whether
or not the search is anchored; assigned to rl_history_search_flags
- rl_history_serarch_reinit: if ANCHORED_SEARCH flag passed, add ^ to
beginning of search string; otherwise search string is unmodified
- rl_history_search_internal: set rl_point appropriately based on
whether or not rl_history_search_flags includes ANCHORED_SEARCH
- rl_history_substr_search_forward: new function, for non-anchored
substring search forward through history for string of characters
preceding rl_point
- rl_history_substr_search_backward: new function, for non-anchored
substring search backward through history for string of characters
preceding rl_point. Original code from Niraj Kulkarni
<kulkarniniraj14@gmail.com>
lib/readline/readline.h
- extern declarations for rl_history_substr_search_{for,back}ward
lib/readline/funmap.c
- history-substring-search-forward: new bindable command, invokes
rl_history_substr_search_forward
- history-substring-search-backward: new bindable command, invokes
rl_history_substr_search_backward
lib/readline/doc/{rluser.texi,readline.3}
- document history-substring-search-forward and
history-substring-search-backward
5/27
----
{nojobs,jobs}.c
- add support for DONT_REPORT_SIGTERM so that the shell doesn't print
a message when a job exits due to SIGTERM since that's the default
signal sent by the kill builtin. Suggested by Marc Herbert
<mark.herbert@gmail.com>
config-top.h
- DONT_REPORT_SIGTERM: new user-modifiable setting. Commented out
by default
5/28
----
lib/readline/bind.c
- _rl_skip_to_delim: skip to a closing double quote or other delimiter,
allowing backslash to quote any character, including the delimiter
- rl_parse_and_bind: call _rl_skip_to_delim instead of using inline
code
- rl_parse_and_bind: allow quoted strings as the values of string
variables. Variable values without double quotes have trailing
whitespace removed (which still allows embedded whitespace, for
better or worse). Fixes problem with string variables not matching
in `set' command if values happen to have trailing spaces or tabs
(debian bash bug #602762), but introduces slight incompatibility.
5/29
----
doc/{bash.1,bashref.texi}
- clarify unset description to specify that without options, a
variable, then a shell function if there is no variable by that
name, is unset. Fixes discrepancy reported by Mu Qiao
<qiaomuf@gentoo.org>
6/4
----
doc/{bash.1,bashref.texi}
- clarify description of LINES and COLUMNS (and checkwinsize shopt
option) to make it clear that only interactive shells set a
handler for SIGWINCH and update LINES and COLUMNS. Original
report submitted by Jonathan Nieder <jrnieder@gmail.com>
arrayfunc.c
- expand_compound_array_assignment: defer expansion of words between
parens when performing compound assignmnt to an associative array
variable
- assign_compound_array_list: perform the same expansions when doing
a compound array assignment to an associative array variable as
when doing a straight array index assignment. The idea is that
foo=( [ind1]=bar [ind2]=quux)
is the same as
foo[ind1]=bar ; foo[ind2]=quux
This fixes problems with double-expansion and quote removal being
performed on the array indices
+157
View File
@@ -11653,3 +11653,160 @@ sig.c
readline is active, call bashline_set_event_hook to cause
termsig_handler to be called via bash_event_hook when the shell
returns from the signal handler
5/15
----
lib/readline/display.c
- _rl_col_width: Mac OS X has a bug in wcwitdh: it does not return 0
for UTF-8 combining characters. Added workaround dependent on
MACOSX. Fixes problem pointed out by Thomas De Contes
<d.l.tDecontes@free.fr>
5/16
----
lib/readline/rlmbutil.h
- WCWIDTH: wrapper for wcwidth that returns 0 for Unicode combining
characters on systems where wcwidth is broken (e.g., Mac OS X).
lib/readline/{complete,display,mbutil}.c
- use WCWIDTH instead of wcwidth
5/17
----
lib/readline/display.c
- update_line: after computing ofd and nfd, see whether the next
character in ofd is a zero-width combining character. If it is,
back ofd and nfd up one, so the base characters no longer compare
as equivalent. Fixes problem reported by Keith Winstein
<keithw@mit.edu>
lib/readline/nls.c
- _rl_utf8locale: new flag variable, set to non-zero if the current
locale is UTF-8
- utf8locale(): new function, returns 1 if the passed lspec (or the
current locale) indicates that the locale is UTF-8. Called from
_rl_init_eightbit
lib/readline/rlprivate.h
- extern declaration for _rl_utf8locale
locale.c
- locale_utf8locale: new flag variable, set to non-zero if the current
locale is UTF-8 (currently unused)
- locale_isutf8(): new function, returns 1 if the passed lspec (or the
current locale) indicates that the locale is UTF-8. Should be called
whenever the locale or LC_CTYPE value is modified
aclocal.m4
- BASH_WCWIDTH_BROKEN: new test for whether or not wcwidth returns
zero-width characters like unicode combining characters as having
display length 1; define WCWIDTH_BROKEN in this case
config.h.in
- WCWIDTH_BROKEN: new define
lib/readline/rlmbutil.h
- change WCWIDTH macro to use _rl_utf8locale and the full range of
Unicode combining characters (U+0300-U+036F)
5/19
----
lib/readline/rlprivate.h
- _rl_search_context: new member, prevc, will hold character read
prior to lastc
lib/readline/isearch.c
- _rl_isearch_dispatch: if the character causes us to index into
another keymap, save that character in cxt->prevc
- _rl_isearch_dispatch: if we index into another keymap, but don't
find a function that's special to i-search, and the character that
caused us to index into that keymap would have terminated the
search, push back cxt->prevc and cxt->lastc to make it appear as
if `prevc' terminated the search, and execute lastc as a command.
We have to push prevc back so we index into the same keymap before
we read lastc. Fixes bug report from Davor Cubranic
<cubranic@stat.ubc.ca>
5/20
----
expr.c
- expr_bind_variable: pay attention to the return value from
bind_variable and check whether or not we should error out due to
a readonly or noassign variable. Fixes bug reported by Eric
Blake <eblake@redhat.com>
5/26
----
lib/readline/search.c
- include histlib.h for ANCHORED_SEARCH defines
- rl_history_search_flags: new variable, holds ANCHORED_SEARCH flag for
the duration of a history search
- rl_history_search_reinit: takes a new flags variable, defines whether
or not the search is anchored; assigned to rl_history_search_flags
- rl_history_serarch_reinit: if ANCHORED_SEARCH flag passed, add ^ to
beginning of search string; otherwise search string is unmodified
- rl_history_search_internal: set rl_point appropriately based on
whether or not rl_history_search_flags includes ANCHORED_SEARCH
- rl_history_substr_search_forward: new function, for non-anchored
substring search forward through history for string of characters
preceding rl_point
- rl_history_substr_search_backward: new function, for non-anchored
substring search backward through history for string of characters
preceding rl_point. Original code from Niraj Kulkarni
<kulkarniniraj14@gmail.com>
lib/readline/readline.h
- extern declarations for rl_history_substr_search_{for,back}ward
lib/readline/funmap.c
- history-substring-search-forward: new bindable command, invokes
rl_history_substr_search_forward
- history-substring-search-backward: new bindable command, invokes
rl_history_substr_search_backward
lib/readline/doc/{rluser.texi,readline.3}
- document history-substring-search-forward and
history-substring-search-backward
5/27
----
{nojobs,jobs}.c
- add support for DONT_REPORT_SIGTERM so that the shell doesn't print
a message when a job exits due to SIGTERM since that's the default
signal sent by the kill builtin. Suggested by Marc Herbert
<mark.herbert@gmail.com>
config-top.h
- DONT_REPORT_SIGTERM: new user-modifiable setting. Commented out
by default
5/28
----
lib/readline/bind.c
- _rl_skip_to_delim: skip to a closing double quote or other delimiter,
allowing backslash to quote any character, including the delimiter
- rl_parse_and_bind: call _rl_skip_to_delim instead of using inline
code
- rl_parse_and_bind: allow quoted strings as the values of string
variables. Variable values without double quotes have trailing
whitespace removed (which still allows embedded whitespace, for
better or worse). Fixes problem with string variables not matching
in `set' command if values happen to have trailing spaces or tabs
(debian bash bug #602762), but introduces slight incompatibility.
5/29
----
doc/{bash.1,bashref.texi}
- clarify unset description to specify that without options, a
variable, then a shell function if there is no variable by that
name, is unset. Fixes discrepancy reported by Mu Qiao
<qiaomuf@gentoo.org>
6/4
----
doc/{bash.1,bashref.texi}
- clarify description of LINES and COLUMNS (and checkwinsize shopt
option) to make it clear that only interactive shells set a
handler for SIGWINCH and update LINES and COLUMNS. Original
report submitted by Jonathan Nieder <jrnieder@gmail.com>
+57 -12
View File
@@ -1,6 +1,6 @@
/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
/* Copyright (C) 2001-2010 Free Software Foundation, Inc.
/* Copyright (C) 2001-2011 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -41,6 +41,7 @@ extern int last_command_exit_value;
extern int array_needs_making;
static SHELL_VAR *bind_array_var_internal __P((SHELL_VAR *, arrayind_t, char *, char *, int));
static SHELL_VAR *assign_array_element_internal __P((SHELL_VAR *, char *, char *, char *, int, char *, int));
static char *quote_assign __P((const char *));
static void quote_array_assignment_chars __P((WORD_LIST *));
@@ -237,8 +238,7 @@ assign_array_element (name, value, flags)
char *name, *value;
int flags;
{
char *sub, *vname, *akey;
arrayind_t ind;
char *sub, *vname;
int sublen;
SHELL_VAR *entry;
@@ -255,6 +255,24 @@ assign_array_element (name, value, flags)
}
entry = find_variable (vname);
entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags);
free (vname);
return entry;
}
static SHELL_VAR *
assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
SHELL_VAR *entry;
char *name; /* only used for error messages */
char *vname;
char *sub;
int sublen;
char *value;
int flags;
{
char *akey;
arrayind_t ind;
if (entry && assoc_p (entry))
{
@@ -263,7 +281,6 @@ assign_array_element (name, value, flags)
sub[sublen-1] = ']';
if (akey == 0 || *akey == 0)
{
free (vname);
err_badarraysub (name);
return ((SHELL_VAR *)NULL);
}
@@ -274,14 +291,12 @@ assign_array_element (name, value, flags)
ind = array_expand_index (entry, sub, sublen);
if (ind < 0)
{
free (vname);
err_badarraysub (name);
return ((SHELL_VAR *)NULL);
}
entry = bind_array_variable (vname, ind, value, flags);
}
free (vname);
return (entry);
}
@@ -370,10 +385,13 @@ expand_compound_array_assignment (var, value, flags)
int flags;
{
WORD_LIST *list, *nlist;
WORD_LIST *hd, *tl, *t, *n;
char *val;
int ni;
/* I don't believe this condition is ever true any more. */
/* This condition is true when invoked from the declare builtin with a
command like
declare -a d='([1]="" [2]="bdef" [5]="hello world" "test")' */
if (*value == '(') /*)*/
{
ni = 1;
@@ -390,8 +408,17 @@ expand_compound_array_assignment (var, value, flags)
(ksh93 seems to do this). */
list = parse_string_to_word_list (val, 1, "array assign");
if (var && assoc_p (var))
{
if (val != value)
free (val);
return list;
}
/* If we're using [subscript]=value, we need to quote each [ and ] to
prevent unwanted filename expansion. */
prevent unwanted filename expansion. This doesn't need to be done
for associative array expansion, since that uses a different expansion
function (see assign_compound_array_list below). */
if (list)
quote_array_assignment_chars (list);
@@ -418,7 +445,7 @@ assign_compound_array_list (var, nlist, flags)
HASH_TABLE *h;
WORD_LIST *list;
char *w, *val, *nval;
int len, iflags;
int len, iflags, free_val;
arrayind_t ind, last_ind;
char *akey;
@@ -448,7 +475,10 @@ assign_compound_array_list (var, nlist, flags)
/* We have a word of the form [ind]=value */
if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
{
len = skipsubscript (w, 0, (var && assoc_p (var) != 0));
/* Don't have to handle embedded quotes specially any more, since
associative array subscripts have not been expanded yet (see
above). */
len = skipsubscript (w, 0, 0);
/* XXX - changes for `+=' */
if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
@@ -496,7 +526,11 @@ assign_compound_array_list (var, nlist, flags)
}
else if (assoc_p (var))
{
akey = substring (w, 1, len);
/* This is not performed above, see expand_compound_array_assignment */
w[len] = '\0'; /*[*/
akey = expand_assignment_string_to_string (w+1, 0);
w[len] = ']';
/* And we need to expand the value also, see below */
if (akey == 0 || *akey == 0)
{
err_badarraysub (w);
@@ -511,7 +545,7 @@ assign_compound_array_list (var, nlist, flags)
val = w + len + 3;
}
else
val = w + len + 2;
val = w + len + 2;
}
else if (assoc_p (var))
{
@@ -524,10 +558,21 @@ assign_compound_array_list (var, nlist, flags)
val = w;
}
free_val = 0;
/* See above; we need to expand the value here */
if (assoc_p (var))
{
val = expand_assignment_string_to_string (val, 0);
free_val = 1;
}
if (integer_p (var))
this_command_name = (char *)NULL; /* no command name for errors */
bind_array_var_internal (var, ind, akey, val, iflags);
last_ind++;
if (free_val)
free (val);
}
}
+1042
View File
File diff suppressed because it is too large Load Diff
+1057
View File
File diff suppressed because it is too large Load Diff
+1102
View File
File diff suppressed because it is too large Load Diff
+1087
View File
File diff suppressed because it is too large Load Diff
+58 -13
View File
@@ -1,6 +1,6 @@
/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
/* Copyright (C) 2001-2010 Free Software Foundation, Inc.
/* Copyright (C) 2001-2011 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -41,6 +41,7 @@ extern int last_command_exit_value;
extern int array_needs_making;
static SHELL_VAR *bind_array_var_internal __P((SHELL_VAR *, arrayind_t, char *, char *, int));
static SHELL_VAR *assign_array_element_internal __P((SHELL_VAR *, char *, char *, char *, int, char *, int));
static char *quote_assign __P((const char *));
static void quote_array_assignment_chars __P((WORD_LIST *));
@@ -237,8 +238,7 @@ assign_array_element (name, value, flags)
char *name, *value;
int flags;
{
char *sub, *vname, *akey;
arrayind_t ind;
char *sub, *vname;
int sublen;
SHELL_VAR *entry;
@@ -255,6 +255,24 @@ assign_array_element (name, value, flags)
}
entry = find_variable (vname);
entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags);
free (vname);
return entry;
}
static SHELL_VAR *
assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
SHELL_VAR *entry;
char *name; /* only used for error messages */
char *vname;
char *sub;
int sublen;
char *value;
int flags;
{
char *akey;
arrayind_t ind;
if (entry && assoc_p (entry))
{
@@ -263,7 +281,6 @@ assign_array_element (name, value, flags)
sub[sublen-1] = ']';
if (akey == 0 || *akey == 0)
{
free (vname);
err_badarraysub (name);
return ((SHELL_VAR *)NULL);
}
@@ -274,14 +291,12 @@ assign_array_element (name, value, flags)
ind = array_expand_index (entry, sub, sublen);
if (ind < 0)
{
free (vname);
err_badarraysub (name);
return ((SHELL_VAR *)NULL);
}
entry = bind_array_variable (vname, ind, value, flags);
}
free (vname);
return (entry);
}
@@ -370,10 +385,13 @@ expand_compound_array_assignment (var, value, flags)
int flags;
{
WORD_LIST *list, *nlist;
WORD_LIST *hd, *tl, *t, *n;
char *val;
int ni;
/* I don't believe this condition is ever true any more. */
/* This condition is true when invoked from the declare builtin with a
command like
declare -a d='([1]="" [2]="bdef" [5]="hello world" "test")' */
if (*value == '(') /*)*/
{
ni = 1;
@@ -390,8 +408,17 @@ expand_compound_array_assignment (var, value, flags)
(ksh93 seems to do this). */
list = parse_string_to_word_list (val, 1, "array assign");
if (var && (assoc_p (var))
{
if (val != value)
free (val);
return list;
}
/* If we're using [subscript]=value, we need to quote each [ and ] to
prevent unwanted filename expansion. */
prevent unwanted filename expansion. This doesn't need to be done
for associative array expansion, since that uses a different expansion
function (see assign_compound_array_list below). */
if (list)
quote_array_assignment_chars (list);
@@ -418,7 +445,7 @@ assign_compound_array_list (var, nlist, flags)
HASH_TABLE *h;
WORD_LIST *list;
char *w, *val, *nval;
int len, iflags;
int len, iflags, free_val;
arrayind_t ind, last_ind;
char *akey;
@@ -448,7 +475,10 @@ assign_compound_array_list (var, nlist, flags)
/* We have a word of the form [ind]=value */
if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
{
len = skipsubscript (w, 0, (var && assoc_p (var) != 0));
/* Don't have to handle embedded quotes specially any more, since
associative array subscripts have not been expanded yet (see
above). */
len = skipsubscript (w, 0, 0);
/* XXX - changes for `+=' */
if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
@@ -496,7 +526,11 @@ assign_compound_array_list (var, nlist, flags)
}
else if (assoc_p (var))
{
akey = substring (w, 1, len);
/* This is not performed above, see expand_compound_array_assignment */
w[len] = '\0'; /*[*/
akey = expand_assignment_string_to_string (w+1, 0);
w[len] = ']';
/* And we need to expand the value also, see below */
if (akey == 0 || *akey == 0)
{
err_badarraysub (w);
@@ -511,7 +545,7 @@ assign_compound_array_list (var, nlist, flags)
val = w + len + 3;
}
else
val = w + len + 2;
val = w + len + 2;
}
else if (assoc_p (var))
{
@@ -524,10 +558,21 @@ assign_compound_array_list (var, nlist, flags)
val = w;
}
free_val = 0;
/* See above; we need to expand the value here */
if (assoc_p (var))
{
val = expand_assignment_string_to_string (val, 0);
free_val = 1;
}
if (integer_p (var))
this_command_name = (char *)NULL; /* no command name for errors */
bind_array_var_internal (var, ind, akey, val, iflags);
last_ind++;
if (free_val)
free (val);
}
}
@@ -935,7 +980,7 @@ array_value_internal (s, quoted, flags, rtype, indp)
{
if ((flags & AV_USEIND) == 0 || indp == 0)
{
ind = array_expand_index (t, len);
ind = array_expand_index (var, t, len);
if (ind < 0)
{
/* negative subscripts to indexed arrays count back from end */
+5
View File
@@ -46,6 +46,11 @@
when a job like `cat jobs.c | exit 1' terminates due to a SIGPIPE. */
#define DONT_REPORT_SIGPIPE
/* Define DONT_REPORT_SIGTERM if you don't want to see `Terminates' message
when a job exits due to SIGTERM, since that's the default signal sent
by the kill builtin. */
/* #define DONT_REPORT_SIGTERM */
/* Define DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS if you don't want builtins
like `echo' and `printf' to report errors when output does not succeed
due to EPIPE. */
+121
View File
@@ -0,0 +1,121 @@
/* config-top.h - various user-settable options not under the control of autoconf. */
/* Copyright (C) 2002-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/>.
*/
/* Define CONTINUE_AFTER_KILL_ERROR if you want the kill command to
continue processing arguments after one of them fails. This is
what POSIX.2 specifies. */
#define CONTINUE_AFTER_KILL_ERROR
/* Define BREAK_COMPLAINS if you want the non-standard, but useful
error messages about `break' and `continue' out of context. */
#define BREAK_COMPLAINS
/* Define BUFFERED_INPUT if you want the shell to do its own input
buffering, rather than using stdio. Do not undefine this; it's
required to preserve semantics required by POSIX. */
#define BUFFERED_INPUT
/* Define ONESHOT if you want sh -c 'command' to avoid forking to execute
`command' whenever possible. This is a big efficiency improvement. */
#define ONESHOT
/* Define V9_ECHO if you want to give the echo builtin backslash-escape
interpretation using the -e option, in the style of the Bell Labs 9th
Edition version of echo. You cannot emulate the System V echo behavior
without this option. */
#define V9_ECHO
/* Define DONT_REPORT_SIGPIPE if you don't want to see `Broken pipe' messages
when a job like `cat jobs.c | exit 1' terminates due to a SIGPIPE. */
#define DONT_REPORT_SIGPIPE
/* Define DONT_REPORT_SIGTERM if you don't want to see `Terminates' message
when a job exits due to SIGTERM, since that's the default signal sent
by the kill builtin. */
#define DONT_REPORT_SIGTERM
/* Define DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS if you don't want builtins
like `echo' and `printf' to report errors when output does not succeed
due to EPIPE. */
/* #define DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS */
/* The default value of the PATH variable. */
#ifndef DEFAULT_PATH_VALUE
#define DEFAULT_PATH_VALUE \
"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:."
#endif
/* The value for PATH when invoking `command -p'. This is only used when
the Posix.2 confstr () function, or CS_PATH define are not present. */
#ifndef STANDARD_UTILS_PATH
#define STANDARD_UTILS_PATH \
"/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc"
#endif
/* Default primary and secondary prompt strings. */
#define PPROMPT "\\s-\\v\\$ "
#define SPROMPT "> "
/* Undefine this if you don't want the ksh-compatible behavior of reprinting
the select menu after a valid choice is made only if REPLY is set to NULL
in the body of the select command. The menu is always reprinted if the
reply to the select query is an empty line. */
#define KSH_COMPATIBLE_SELECT
/* System-wide .bashrc file for interactive shells. */
/* #define SYS_BASHRC "/etc/bash.bashrc" */
/* System-wide .bash_logout for login shells. */
/* #define SYS_BASH_LOGOUT "/etc/bash.bash_logout" */
/* Define this to make non-interactive shells begun with argv[0][0] == '-'
run the startup files when not in posix mode. */
/* #define NON_INTERACTIVE_LOGIN_SHELLS */
/* Define this if you want bash to try to check whether it's being run by
sshd and source the .bashrc if so (like the rshd behavior). This checks
for the presence of SSH_CLIENT or SSH2_CLIENT in the initial environment,
which can be fooled under certain not-uncommon circumstances. */
/* #define SSH_SOURCE_BASHRC */
/* Define if you want the case-capitalizing operators (~[~]) and the
`capcase' variable attribute (declare -c). */
#define CASEMOD_CAPCASE
/* This is used as the name of a shell function to call when a command
name is not found. If you want to name it something other than the
default ("command_not_found_handle"), change it here. */
/* #define NOTFOUND_HOOK "command_not_found_handle" */
/* Define if you want each line saved to the history list in bashhist.c:
bash_add_history() to be sent to syslog(). */
/* #define SYSLOG_HISTORY */
#if defined (SYSLOG_HISTORY)
# define SYSLOG_FACILITY LOG_USER
# define SYSLOG_LEVEL LOG_INFO
#endif
/* Define if you want to include code in shell.c to support wordexp(3) */
/* #define WORDEXP_OPTION */
/* Define as 1 if you want to enable code that implements multiple coprocs */
#ifndef MULTIPLE_COPROCS
# define MULTIPLE_COPROCS 0
#endif
+11 -5
View File
@@ -1866,7 +1866,8 @@ A sample value is
.TP
.B COLUMNS
Used by the \fBselect\fP compound command to determine the terminal width
when printing selection lists. Automatically set upon receipt of a
when printing selection lists. Automatically set in an interactive shell
upon receipt of a
.SM
.BR SIGWINCH .
.TP
@@ -2098,7 +2099,8 @@ This variable determines the locale category used for number formatting.
.TP
.B LINES
Used by the \fBselect\fP compound command to determine the column length
for printing selection lists. Automatically set upon receipt of a
for printing selection lists. Automatically set by an interactive shell
upon receipt of a
.SM
.BR SIGWINCH .
.TP
@@ -8913,7 +8915,8 @@ above). The shell always
postpones exiting if any jobs are stopped.
.TP 8
.B checkwinsize
If set, \fBbash\fP checks the window size after each command
If set, \fBbash\fP checks the window size after each command when running
interactively
and, if necessary, updates the values of
.SM
.B LINES
@@ -9669,11 +9672,11 @@ is not a defined alias.
For each
.IR name ,
remove the corresponding variable or function.
If no options are supplied, or the
If the
.B \-v
option is given, each
.I name
refers to a shell variable.
refers to a shell variable, and that variable is removed.
Read-only variables may not be unset.
If
.B \-f
@@ -9681,6 +9684,9 @@ is specified, each
.I name
refers to a shell function, and the function definition
is removed.
If no options are supplied, each \fIname\fP refers to a variable; if
there is no variable by that name, any function with that name is
unset.
Each unset variable or function is removed from the environment
passed to subsequent commands.
If any of
+29 -14
View File
@@ -5,12 +5,12 @@
.\" Case Western Reserve University
.\" chet@po.cwru.edu
.\"
.\" Last Change: Tue Dec 28 13:41:43 EST 2010
.\" Last Change: Mon May 9 12:23:35 EDT 2011
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
.TH BASH 1 "2010 December 28" "GNU Bash-4.2"
.TH BASH 1 "2011 May 9" "GNU Bash 4.2"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
@@ -646,7 +646,10 @@ AND and OR lists is the exit status of the last command
executed in the list.
.SS Compound Commands
.PP
A \fIcompound command\fP is one of the following:
A \fIcompound command\fP is one of the following.
In most cases a \fIlist\fP in a command's description may be separated from
the rest of the command by one or more newlines, and may be followed by a
newline in place of a semicolon.
.TP
(\fIlist\fP)
\fIlist\fP is executed in a subshell environment (see
@@ -911,7 +914,7 @@ The format for a coprocess is:
.RE
.PP
This creates a coprocess named \fINAME\fP.
If \fINAME\fP is not supplied, the default name is \fICOPROC\fP.
If \fINAME\fP is not supplied, the default name is \fBCOPROC\fP.
\fINAME\fP must not be supplied if \fIcommand\fP is a \fIsimple
command\fP (see above); otherwise, it is interpreted as the first word
of the simple command.
@@ -1465,7 +1468,8 @@ The shell function
\fB${BASH_SOURCE[\fP\fI$i+1\fP\fB]}\fP.
.TP
.B BASH_SUBSHELL
Incremented by one each time a subshell or subshell environment is spawned.
Incremented by one within each subshell or subshell environment when
the shell begins executing in that environment.
The initial value is 0.
.TP
.B BASH_VERSINFO
@@ -2163,8 +2167,8 @@ The default path is system-dependent,
and is set by the administrator who installs
.BR bash .
A common value is
.if t \f(CW/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin\fP.
.if n ``/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin''.
.if t \f(CW/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin\fP.
.if n ``/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin''.
.TP
.B POSIXLY_CORRECT
If this variable is in the environment when \fBbash\fP starts, the shell
@@ -3123,7 +3127,11 @@ If one of these characters appears, then the word is
regarded as a
.IR pattern ,
and replaced with an alphabetically sorted list of
file names matching the pattern.
file names matching the pattern
(see
.SM
.B "Pattern Matching"
below).
If no matching file names are found,
and the shell option
.B nullglob
@@ -3528,6 +3536,7 @@ This is semantically equivalent to
\fB>\fP\fIword\fP 2\fB>&\fP1
.RE
.PP
(see \fBDuplicating File Descriptors\fP below).
.SS Appending Standard Output and Standard Error
.PP
This construct allows both the
@@ -3548,6 +3557,8 @@ This is semantically equivalent to
.PP
\fB>>\fP\fIword\fP 2\fB>&\fP1
.RE
.PP
(see \fBDuplicating File Descriptors\fP below).
.SS Here Documents
.PP
This type of redirection instructs the shell to read input from the
@@ -7330,7 +7341,7 @@ does not specify a valid job.
.TP
\fBecho\fP [\fB\-neE\fP] [\fIarg\fP ...]
Output the \fIarg\fPs, separated by spaces, followed by a newline.
The return status is always 0.
The return status is 0 unless a write error occurs.
If \fB\-n\fP is specified, the trailing newline is
suppressed. If the \fB\-e\fP option is given, interpretation of
the following backslash-escaped characters is enabled. The
@@ -8519,9 +8530,10 @@ by default for interactive shells on systems that support
it (see
.SM
.B JOB CONTROL
above). Background processes run in a separate process
group and a line containing their exit status is printed
upon their completion.
above).
All processes run in a separate process group.
When a background job completes, the shell prints a line
containing its exit status.
.TP 8
.B \-n
Read commands but do not execute them. This may be used to
@@ -9657,11 +9669,11 @@ is not a defined alias.
For each
.IR name ,
remove the corresponding variable or function.
If no options are supplied, or the
If the
.B \-v
option is given, each
.I name
refers to a shell variable.
refers to a shell variable, and that variable is removed.
Read-only variables may not be unset.
If
.B \-f
@@ -9669,6 +9681,9 @@ is specified, each
.I name
refers to a shell function, and the function definition
is removed.
If no options are supplied, each \fIname\fP refers to a variable; if
there is no variable by that name, any function with that name is
unset.
Each unset variable or function is removed from the environment
passed to subsequent commands.
If any of
+16 -7
View File
@@ -185,7 +185,7 @@ Shells also provide a small set of built-in
commands (@dfn{builtins}) implementing functionality impossible
or inconvenient to obtain via separate utilities.
For example, @code{cd}, @code{break}, @code{continue}, and
@code{exec}) cannot be implemented outside of the shell because
@code{exec} cannot be implemented outside of the shell because
they directly manipulate the shell itself.
The @code{history}, @code{getopts}, @code{kill}, or @code{pwd}
builtins, among others, could be implemented in separate utilities,
@@ -3368,10 +3368,13 @@ results in permissions of @code{755}.
unset [-fv] [@var{name}]
@end example
Each variable or function @var{name} is removed.
If no options are supplied, or the @option{-v} option is given, each
@var{name} refers to a shell variable.
If the @option{-v} option is given, each
@var{name} refers to a shell variable and that variable is remvoved.
If the @option{-f} option is given, the @var{name}s refer to shell
functions, and the function definition is removed.
If no options are supplied, each @var{name} refers to a variable; if
there is no variable by that name, any function with that name is
unset.
Readonly variables and functions may not be unset.
The return status is zero unless a @var{name} is readonly.
@end table
@@ -4510,8 +4513,8 @@ intervening command (@pxref{Job Control}).
The shell always postpones exiting if any jobs are stopped.
@item checkwinsize
If set, Bash checks the window size after each command
and, if necessary, updates the values of
If set, Bash checks the window size after each command when running
interactively and, if necessary, updates the values of
@env{LINES} and @env{COLUMNS}.
@item cmdhist
@@ -5005,7 +5008,8 @@ being closed.
@item COLUMNS
Used by the @code{select} command to determine the terminal width
when printing selection lists. Automatically set upon receipt of a
when printing selection lists. Automatically set by an interactive shell
upon receipt of a
@code{SIGWINCH}.
@item COMP_CWORD
@@ -5294,7 +5298,8 @@ The line number in the script or shell function currently executing.
@item LINES
Used by the @code{select} command to determine the column length
for printing selection lists. Automatically set upon receipt of a
for printing selection lists. Automatically set by an interactive shell
upon receipt of a
@code{SIGWINCH}.
@item MACHTYPE
@@ -6742,6 +6747,10 @@ variable in a @code{for} statement or the selection variable in a
@item
Process substitution is not available.
@item
While variable indirection is available, it may not be applied to the
@samp{#} and @samp{?} special parameters.
@item
Assignment statements preceding @sc{posix} special builtins
persist in the shell environment after the builtin completes.
+30 -10
View File
@@ -185,7 +185,7 @@ Shells also provide a small set of built-in
commands (@dfn{builtins}) implementing functionality impossible
or inconvenient to obtain via separate utilities.
For example, @code{cd}, @code{break}, @code{continue}, and
@code{exec}) cannot be implemented outside of the shell because
@code{exec} cannot be implemented outside of the shell because
they directly manipulate the shell itself.
The @code{history}, @code{getopts}, @code{kill}, or @code{pwd}
builtins, among others, could be implemented in separate utilities,
@@ -753,6 +753,10 @@ terminated by a corresponding reserved word or operator.
Any redirections (@pxref{Redirections}) associated with a compound command
apply to all commands within that compound command unless explicitly overridden.
In most cases a list of commands in a compound command's description may be
separated from the rest of the command by one or more newlines, and may be
followed by a newline in place of a semicolon.
Bash provides looping constructs, conditional commands, and mechanisms
to group commands and execute them as a unit.
@@ -1554,7 +1558,7 @@ This mechanism is similar to
@var{filename expansion} (@pxref{Filename Expansion}),
but the file names generated need not exist.
Patterns to be brace expanded take the form of an optional @var{preamble},
followed by either a series of comma-separated strings or a seqeunce expression
followed by either a series of comma-separated strings or a sequence expression
between a pair of braces,
followed by an optional @var{postscript}.
The preamble is prefixed to each string contained within the braces, and
@@ -2044,7 +2048,8 @@ After word splitting, unless the @option{-f} option has been set
If one of these characters appears, then the word is
regarded as a @var{pattern},
and replaced with an alphabetically sorted list of
file names matching the pattern. If no matching file names are found,
file names matching the pattern (@pxref{Pattern Matching}).
If no matching file names are found,
and the shell option @code{nullglob} is disabled, the word is left
unchanged.
If the @code{nullglob} option is set, and no matches are found, the word
@@ -2337,6 +2342,7 @@ This is semantically equivalent to
@example
>@var{word} 2>&1
@end example
(see Duplicating File Descriptors below).
@subsection Appending Standard Output and Standard Error
This construct allows both the
@@ -2354,6 +2360,7 @@ This is semantically equivalent to
@example
>>@var{word} 2>&1
@end example
(see Duplicating File Descriptors below).
@subsection Here Documents
This type of redirection instructs the shell to read input from the
@@ -3361,10 +3368,13 @@ results in permissions of @code{755}.
unset [-fv] [@var{name}]
@end example
Each variable or function @var{name} is removed.
If no options are supplied, or the @option{-v} option is given, each
@var{name} refers to a shell variable.
If the @option{-v} option is given, each
@var{name} refers to a shell variable and that variable is remvoved.
If the @option{-f} option is given, the @var{name}s refer to shell
functions, and the function definition is removed.
If no options are supplied, each @var{name} refers to a variable; if
there is no variable by that name, any function with that name is
unset.
Readonly variables and functions may not be unset.
The return status is zero unless a @var{name} is readonly.
@end table
@@ -3641,7 +3651,7 @@ echo [-neE] [@var{arg} @dots{}]
@end example
Output the @var{arg}s, separated by spaces, terminated with a
newline.
The return status is always 0.
The return status is 0 unless a write error occurs.
If @option{-n} is specified, the trailing newline is suppressed.
If the @option{-e} option is given, interpretation of the following
backslash-escaped characters is enabled.
@@ -4208,6 +4218,9 @@ the command name.
@item -m
Job control is enabled (@pxref{Job Control}).
All processes run in a separate process group.
When a background job completes, the shell prints a line
containing its exit status.
@item -n
Read commands but do not execute them; this may be used to check a
@@ -4945,7 +4958,8 @@ The shell function @code{$@{FUNCNAME[$i]@}} is defined in the file
@code{$@{BASH_SOURCE[$i]@}} and called from @code{$@{BASH_SOURCE[$i+1]@}}
@item BASH_SUBSHELL
Incremented by one each time a subshell or subshell environment is spawned.
Incremented by one within each subshell or subshell environment when
the shell begins executing in that environment.
The initial value is 0.
@item BASH_VERSINFO
@@ -6248,9 +6262,6 @@ name[@var{subscript}]=@var{value}
@noindent
The @var{subscript}
is treated as an arithmetic expression that must evaluate to a number.
If @var{subscript} evaluates to a number less than zero, it is used as
an offset from one greater than the array's maximum index (so a subcript
of -1 refers to the last element of the array).
To explicitly declare an array, use
@example
declare -a @var{name}
@@ -6317,6 +6328,11 @@ If @var{subscript} is @samp{@@} or
@samp{*}, the expansion is the number of elements in the array.
Referencing an array variable without a subscript is equivalent to
referencing with a subscript of 0.
If the @var{subscript}
used to reference an element of an indexed array
evaluates to a number less than zero, it is used as
an offset from one greater than the array's maximum index (so a subcript
of -1 refers to the last element of the array).
An array variable is considered set if a subscript has been assigned a
value. The null string is a valid value.
@@ -6729,6 +6745,10 @@ variable in a @code{for} statement or the selection variable in a
@item
Process substitution is not available.
@item
While variable indirection is available, it may not be applied to the
@samp{#} and @samp{?} special parameters.
@item
Assignment statements preceding @sc{posix} special builtins
persist in the shell environment after the builtin completes.
+3
View File
@@ -3556,6 +3556,9 @@ notify_of_job_status ()
case JDEAD:
if (interactive_shell == 0 && termsig && WIFSIGNALED (s) &&
termsig != SIGINT &&
#if defined (DONT_REPORT_SIGTERM)
termsig != SIGTERM &&
#endif
#if defined (DONT_REPORT_SIGPIPE)
termsig != SIGPIPE &&
#endif
+41 -14
View File
@@ -3,7 +3,7 @@
/* This file works with both POSIX and BSD systems. It implements job
control. */
/* Copyright (C) 1989-2010 Free Software Foundation, Inc.
/* Copyright (C) 1989-2011 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -2212,6 +2212,10 @@ wait_for_background_pids ()
#define INVALID_SIGNAL_HANDLER (SigHandler *)wait_for_background_pids
static SigHandler *old_sigint_handler = INVALID_SIGNAL_HANDLER;
static int wait_sigint_received;
static int child_caught_sigint;
static int waiting_for_child;
static void
restore_sigint_handler ()
{
@@ -2219,11 +2223,10 @@ restore_sigint_handler ()
{
set_signal_handler (SIGINT, old_sigint_handler);
old_sigint_handler = INVALID_SIGNAL_HANDLER;
waiting_for_child = 0;
}
}
static int wait_sigint_received;
/* Handle SIGINT while we are waiting for children in a script to exit.
The `wait' builtin should be interruptible, but all others should be
effectively ignored (i.e. not cause the shell to exit). */
@@ -2256,7 +2259,14 @@ wait_sigint_handler (sig)
/* XXX - should this be interrupt_state? If it is, the shell will act
as if it got the SIGINT interrupt. */
wait_sigint_received = 1;
if (waiting_for_child)
wait_sigint_received = 1;
else
{
last_command_exit_value = 128+SIGINT;
restore_sigint_handler ();
kill (getpid (), SIGINT);
}
/* Otherwise effectively ignore the SIGINT and allow the running job to
be killed. */
@@ -2392,10 +2402,11 @@ wait_for (pid)
substitution. */
/* This is possibly a race condition -- should it go in stop_pipeline? */
wait_sigint_received = 0;
wait_sigint_received = child_caught_sigint = 0;
if (job_control == 0 || (subshell_environment&SUBSHELL_COMSUB))
{
old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler);
waiting_for_child = 0;
if (old_sigint_handler == SIG_IGN)
set_signal_handler (SIGINT, old_sigint_handler);
}
@@ -2447,7 +2458,9 @@ wait_for (pid)
sigaction (SIGCHLD, &act, &oact);
# endif
queue_sigchld = 1;
waiting_for_child++;
r = waitchld (pid, 1);
waiting_for_child--;
# if defined (MUST_UNBLOCK_CHLD)
sigaction (SIGCHLD, &oact, (struct sigaction *)NULL);
sigprocmask (SIG_SETMASK, &chldset, (sigset_t *)NULL);
@@ -2489,6 +2502,9 @@ wait_for (pid)
}
while (PRUNNING (child) || (job != NO_JOB && RUNNING (job)));
/* Restore the original SIGINT signal handler before we return. */
restore_sigint_handler ();
/* The exit state of the command is either the termination state of the
child, or the termination state of the job. If a job, the status
of the last child in the pipeline is the significant one. If the command
@@ -2585,11 +2601,10 @@ if (job == NO_JOB)
and being killed by the SIGINT to pass the status back to our
parent. */
s = job_signal_status (job);
if (WIFSIGNALED (s) && WTERMSIG (s) == SIGINT && signal_is_trapped (SIGINT) == 0)
if (child_caught_sigint == 0 && signal_is_trapped (SIGINT) == 0)
{
UNBLOCK_CHILD (oset);
restore_sigint_handler ();
old_sigint_handler = set_signal_handler (SIGINT, SIG_DFL);
if (old_sigint_handler == SIG_IGN)
restore_sigint_handler ();
@@ -2615,9 +2630,6 @@ wait_for_return:
UNBLOCK_CHILD (oset);
/* Restore the original SIGINT signal handler before we return. */
restore_sigint_handler ();
return (termination_state);
}
@@ -3117,9 +3129,23 @@ waitchld (wpid, block)
/* If waitpid returns 0, there are running children. If it returns -1,
the only other error POSIX says it can return is EINTR. */
CHECK_TERMSIG;
/* If waitpid returns -1/EINTR and the shell saw a SIGINT, then we
assume the child has blocked or handled SIGINT. In that case, we
require the child to actually die due to SIGINT to act on the
SIGINT we received; otherwise we assume the child handled it and
let it go. */
if (pid < 0 && errno == EINTR && wait_sigint_received)
child_caught_sigint = 1;
if (pid <= 0)
continue; /* jumps right to the test */
/* If the child process did die due to SIGINT, forget our assumption
that it caught or otherwise handled it. */
if (WIFSIGNALED (status) && WTERMSIG (status) == SIGINT)
child_caught_sigint = 0;
/* children_exited is used to run traps on SIGCHLD. We don't want to
run the trap if a process is just being continued. */
if (WIFCONTINUED(status) == 0)
@@ -3307,7 +3333,7 @@ set_job_status_and_cleanup (job)
does not exit due to SIGINT, run the trap handler but do not
otherwise act as if we got the interrupt. */
if (wait_sigint_received && interactive_shell == 0 &&
WIFSIGNALED (child->status) == 0 && IS_FOREGROUND (job) &&
child_caught_sigint && IS_FOREGROUND (job) &&
signal_is_trapped (SIGINT))
{
int old_frozen;
@@ -3329,7 +3355,8 @@ set_job_status_and_cleanup (job)
signals are sent to process groups) or via kill(2) to the foreground
process by another process (or itself). If the shell did receive the
SIGINT, it needs to perform normal SIGINT processing. */
else if (wait_sigint_received && (WTERMSIG (child->status) == SIGINT) &&
else if (wait_sigint_received &&
child_caught_sigint == 0 &&
IS_FOREGROUND (job) && IS_JOBCONTROL (job) == 0)
{
int old_frozen;
@@ -3369,7 +3396,7 @@ set_job_status_and_cleanup (job)
temp_handler = trap_to_sighandler (SIGINT);
restore_sigint_handler ();
if (temp_handler == SIG_DFL)
termsig_handler (SIGINT);
termsig_handler (SIGINT); /* XXX */
else if (temp_handler != SIG_IGN)
(*temp_handler) (SIGINT);
}
+62 -48
View File
@@ -72,11 +72,15 @@ extern char *strchr (), *strrchr ();
/* Variables exported by this file. */
Keymap rl_binding_keymap;
static int _rl_skip_to_delim PARAMS((char *, int, int));
static char *_rl_read_file PARAMS((char *, size_t *));
static void _rl_init_file_error PARAMS((const char *));
static int _rl_read_init_file PARAMS((const char *, int));
static int glean_key_from_name PARAMS((char *));
static int find_boolean_var PARAMS((const char *));
static int find_string_var PARAMS((const char *));
static char *_rl_get_string_variable_value PARAMS((const char *));
static int substring_member_of_array PARAMS((const char *, const char * const *));
@@ -1157,6 +1161,38 @@ handle_parser_directive (statement)
return (1);
}
/* Start at STRING[START] and look for DELIM. Return I where STRING[I] ==
DELIM or STRING[I] == 0. DELIM is usually a double quote. */
static int
_rl_skip_to_delim (string, start, delim)
char *string;
int start, delim;
{
int i, c, passc;
for (i = start,passc = 0; c = string[i]; i++)
{
if (passc)
{
passc = 0;
if (c == 0)
break;
continue;
}
if (c == '\\')
{
passc = 1;
continue;
}
if (c == delim)
break;
}
return i;
}
/* Read the binding command from STRING and perform it.
A key binding command looks like: Keyname: function-name\0,
a variable binding command looks like: set variable value.
@@ -1172,7 +1208,7 @@ rl_parse_and_bind (string)
while (string && whitespace (*string))
string++;
if (!string || !*string || *string == '#')
if (string == 0 || *string == 0 || *string == '#')
return 0;
/* If this is a parser directive, act on it. */
@@ -1192,31 +1228,16 @@ rl_parse_and_bind (string)
backslash to quote characters in the key expression. */
if (*string == '"')
{
int passc = 0;
i = _rl_skip_to_delim (string, 1, '"');
for (i = 1; c = string[i]; i++)
{
if (passc)
{
passc = 0;
continue;
}
if (c == '\\')
{
passc++;
continue;
}
if (c == '"')
break;
}
/* If we didn't find a closing quote, abort the line. */
if (string[i] == '\0')
{
_rl_init_file_error ("no closing `\"' in key binding");
return 1;
}
else
i++; /* skip past closing double quote */
}
/* Advance to the colon (:) or whitespace which separates the two objects. */
@@ -1236,6 +1257,7 @@ rl_parse_and_bind (string)
if (_rl_stricmp (string, "set") == 0)
{
char *var, *value, *e;
int s;
var = string + i;
/* Make VAR point to start of variable name. */
@@ -1243,25 +1265,36 @@ rl_parse_and_bind (string)
/* Make VALUE point to start of value string. */
value = var;
while (*value && !whitespace (*value)) value++;
while (*value && whitespace (*value) == 0) value++;
if (*value)
*value++ = '\0';
while (*value && whitespace (*value)) value++;
/* Strip trailing whitespace from values to boolean variables. Temp
fix until I get a real quoted-string parser here. */
i = find_boolean_var (var);
if (i >= 0)
/* Strip trailing whitespace from values of boolean variables. */
if (find_boolean_var (var) >= 0)
{
/* remove trailing whitespace */
remove_trailing:
e = value + strlen (value) - 1;
while (e >= value && whitespace (*e))
e--;
e++; /* skip back to whitespace or EOS */
if (*e && e >= value)
*e = '\0';
}
else if ((i = find_string_var (var)) >= 0)
{
/* Allow quoted strings in variable values */
if (*value == '"')
{
i = _rl_skip_to_delim (value, 1, *value);
value[i] = '\0';
}
else
goto remove_trailing;
}
rl_variable_bind (var, value);
return 0;
}
@@ -1282,32 +1315,13 @@ rl_parse_and_bind (string)
the quoted string delimiter, like the shell. */
if (*funname == '\'' || *funname == '"')
{
int delimiter, passc;
delimiter = string[i++];
for (passc = 0; c = string[i]; i++)
{
if (passc)
{
passc = 0;
continue;
}
if (c == '\\')
{
passc = 1;
continue;
}
if (c == delimiter)
break;
}
if (c)
i = _rl_skip_to_delim (string, i+1, *funname);
if (string[i])
i++;
}
/* Advance to the end of the string. */
for (; string[i] && !whitespace (string[i]); i++);
for (; string[i] && whitespace (string[i]) == 0; i++);
/* No extra whitespace at the end of the string. */
string[i] = '\0';
@@ -1367,7 +1381,7 @@ rl_parse_and_bind (string)
/* Get the actual character we want to deal with. */
kname = strrchr (string, '-');
if (!kname)
if (kname == 0)
kname = string;
else
kname++;
+2417
View File
File diff suppressed because it is too large Load Diff
+21 -6
View File
@@ -738,15 +738,30 @@ using a non-incremental search for a string supplied by the user.
Search forward through the history using a non-incremental search
for a string supplied by the user.
.TP
.B history\-search\-forward
Search forward through the history for the string of characters
between the start of the current line and the current cursor
position (the \fIpoint\fP).
This is a non-incremental search.
.TP
.B history\-search\-backward
Search backward through the history for the string of characters
between the start of the current line and the current cursor
position (the \fIpoint\fP).
The search string must match at the beginning of a history line.
This is a non-incremental search.
.TP
.B history\-search\-forward
Search forward through the history for the string of characters
between the start of the current line and the point.
The search string must match at the beginning of a history line.
This is a non-incremental search.
.TP
.B history\-substring\-search\-backward
Search backward through the history for the string of characters
between the start of the current line and the current cursor
position (the \fIpoint\fP).
The search string may match anywhere in a history line.
This is a non-incremental search.
.TP
.B history\-substring\-search\-forward
Search forward through the history for the string of characters
between the start of the current line and the point.
The search string may match anywhere in a history line.
This is a non-incremental search.
.TP
.B yank\-nth\-arg (M\-C\-y)
File diff suppressed because it is too large Load Diff
+19 -2
View File
@@ -1100,13 +1100,30 @@ for a string supplied by the user.
@item history-search-forward ()
Search forward through the history for the string of characters
between the start of the current line and the point.
The search string must match at the beginning of a history line.
This is a non-incremental search.
By default, this command is unbound.
@item history-search-backward ()
Search backward through the history for the string of characters
between the start of the current line and the point. This
is a non-incremental search. By default, this command is unbound.
between the start of the current line and the point.
The search string must match at the beginning of a history line.
This is a non-incremental search.
By default, this command is unbound.
@item history-substr-search-forward ()
Search forward through the history for the string of characters
between the start of the current line and the point.
The search string may match anywhere in a history line.
This is a non-incremental search.
By default, this command is unbound.
@item history-substr-search-backward ()
Search backward through the history for the string of characters
between the start of the current line and the point.
The search string may match anywhere in a history line.
This is a non-incremental search.
By default, this command is unbound.
@item yank-nth-arg (M-C-y)
Insert the first argument to the previous command (usually
File diff suppressed because it is too large Load Diff
+2
View File
@@ -98,6 +98,8 @@ static const FUNMAP default_funmap[] = {
{ "forward-word", rl_forward_word },
{ "history-search-backward", rl_history_search_backward },
{ "history-search-forward", rl_history_search_forward },
{ "history-substring-search-backward", rl_history_substr_search_backward },
{ "history-substring-search-forward", rl_history_substr_search_forward },
{ "insert-comment", rl_insert_comment },
{ "insert-completions", rl_insert_completions },
{ "kill-whole-line", rl_kill_full_line },
+263
View File
@@ -0,0 +1,263 @@
/* funmap.c -- attach names to functions. */
/* Copyright (C) 1987-2010 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
#if !defined (BUFSIZ)
#include <stdio.h>
#endif /* BUFSIZ */
#if defined (HAVE_STDLIB_H)
# include <stdlib.h>
#else
# include "ansi_stdlib.h"
#endif /* HAVE_STDLIB_H */
#include "rlconf.h"
#include "readline.h"
#include "xmalloc.h"
#ifdef __STDC__
typedef int QSFUNC (const void *, const void *);
#else
typedef int QSFUNC ();
#endif
extern int _rl_qsort_string_compare PARAMS((char **, char **));
FUNMAP **funmap;
static int funmap_size;
static int funmap_entry;
/* After initializing the function map, this is the index of the first
program specific function. */
int funmap_program_specific_entry_start;
static const FUNMAP default_funmap[] = {
{ "abort", rl_abort },
{ "accept-line", rl_newline },
{ "arrow-key-prefix", rl_arrow_keys },
{ "backward-byte", rl_backward_byte },
{ "backward-char", rl_backward_char },
{ "backward-delete-char", rl_rubout },
{ "backward-kill-line", rl_backward_kill_line },
{ "backward-kill-word", rl_backward_kill_word },
{ "backward-word", rl_backward_word },
{ "beginning-of-history", rl_beginning_of_history },
{ "beginning-of-line", rl_beg_of_line },
{ "call-last-kbd-macro", rl_call_last_kbd_macro },
{ "capitalize-word", rl_capitalize_word },
{ "character-search", rl_char_search },
{ "character-search-backward", rl_backward_char_search },
{ "clear-screen", rl_clear_screen },
{ "complete", rl_complete },
{ "copy-backward-word", rl_copy_backward_word },
{ "copy-forward-word", rl_copy_forward_word },
{ "copy-region-as-kill", rl_copy_region_to_kill },
{ "delete-char", rl_delete },
{ "delete-char-or-list", rl_delete_or_show_completions },
{ "delete-horizontal-space", rl_delete_horizontal_space },
{ "digit-argument", rl_digit_argument },
{ "do-lowercase-version", rl_do_lowercase_version },
{ "downcase-word", rl_downcase_word },
{ "dump-functions", rl_dump_functions },
{ "dump-macros", rl_dump_macros },
{ "dump-variables", rl_dump_variables },
{ "emacs-editing-mode", rl_emacs_editing_mode },
{ "end-kbd-macro", rl_end_kbd_macro },
{ "end-of-history", rl_end_of_history },
{ "end-of-line", rl_end_of_line },
{ "exchange-point-and-mark", rl_exchange_point_and_mark },
{ "forward-backward-delete-char", rl_rubout_or_delete },
{ "forward-byte", rl_forward_byte },
{ "forward-char", rl_forward_char },
{ "forward-search-history", rl_forward_search_history },
{ "forward-word", rl_forward_word },
{ "history-search-backward", rl_history_search_backward },
{ "history-search-forward", rl_history_search_forward },
{ "insert-comment", rl_insert_comment },
{ "insert-completions", rl_insert_completions },
{ "kill-whole-line", rl_kill_full_line },
{ "kill-line", rl_kill_line },
{ "kill-region", rl_kill_region },
{ "kill-word", rl_kill_word },
{ "menu-complete", rl_menu_complete },
{ "menu-complete-backward", rl_backward_menu_complete },
{ "next-history", rl_get_next_history },
{ "non-incremental-forward-search-history", rl_noninc_forward_search },
{ "non-incremental-reverse-search-history", rl_noninc_reverse_search },
{ "non-incremental-forward-search-history-again", rl_noninc_forward_search_again },
{ "non-incremental-reverse-search-history-again", rl_noninc_reverse_search_again },
{ "old-menu-complete", rl_old_menu_complete },
{ "overwrite-mode", rl_overwrite_mode },
#ifdef __CYGWIN__
{ "paste-from-clipboard", rl_paste_from_clipboard },
#endif
{ "possible-completions", rl_possible_completions },
{ "previous-history", rl_get_previous_history },
{ "quoted-insert", rl_quoted_insert },
{ "re-read-init-file", rl_re_read_init_file },
{ "redraw-current-line", rl_refresh_line},
{ "reverse-search-history", rl_reverse_search_history },
{ "revert-line", rl_revert_line },
{ "self-insert", rl_insert },
{ "set-mark", rl_set_mark },
{ "skip-csi-sequence", rl_skip_csi_sequence },
{ "start-kbd-macro", rl_start_kbd_macro },
{ "tab-insert", rl_tab_insert },
{ "tilde-expand", rl_tilde_expand },
{ "transpose-chars", rl_transpose_chars },
{ "transpose-words", rl_transpose_words },
{ "tty-status", rl_tty_status },
{ "undo", rl_undo_command },
{ "universal-argument", rl_universal_argument },
{ "unix-filename-rubout", rl_unix_filename_rubout },
{ "unix-line-discard", rl_unix_line_discard },
{ "unix-word-rubout", rl_unix_word_rubout },
{ "upcase-word", rl_upcase_word },
{ "yank", rl_yank },
{ "yank-last-arg", rl_yank_last_arg },
{ "yank-nth-arg", rl_yank_nth_arg },
{ "yank-pop", rl_yank_pop },
#if defined (VI_MODE)
{ "vi-append-eol", rl_vi_append_eol },
{ "vi-append-mode", rl_vi_append_mode },
{ "vi-arg-digit", rl_vi_arg_digit },
{ "vi-back-to-indent", rl_vi_back_to_indent },
{ "vi-backward-bigword", rl_vi_bWord },
{ "vi-backward-word", rl_vi_bword },
{ "vi-bWord", rl_vi_bWord },
{ "vi-bword", rl_vi_bword },
{ "vi-change-case", rl_vi_change_case },
{ "vi-change-char", rl_vi_change_char },
{ "vi-change-to", rl_vi_change_to },
{ "vi-char-search", rl_vi_char_search },
{ "vi-column", rl_vi_column },
{ "vi-complete", rl_vi_complete },
{ "vi-delete", rl_vi_delete },
{ "vi-delete-to", rl_vi_delete_to },
{ "vi-eWord", rl_vi_eWord },
{ "vi-editing-mode", rl_vi_editing_mode },
{ "vi-end-bigword", rl_vi_eWord },
{ "vi-end-word", rl_vi_end_word },
{ "vi-eof-maybe", rl_vi_eof_maybe },
{ "vi-eword", rl_vi_eword },
{ "vi-fWord", rl_vi_fWord },
{ "vi-fetch-history", rl_vi_fetch_history },
{ "vi-first-print", rl_vi_first_print },
{ "vi-forward-bigword", rl_vi_fWord },
{ "vi-forward-word", rl_vi_fword },
{ "vi-fword", rl_vi_fword },
{ "vi-goto-mark", rl_vi_goto_mark },
{ "vi-insert-beg", rl_vi_insert_beg },
{ "vi-insertion-mode", rl_vi_insertion_mode },
{ "vi-match", rl_vi_match },
{ "vi-movement-mode", rl_vi_movement_mode },
{ "vi-next-word", rl_vi_next_word },
{ "vi-overstrike", rl_vi_overstrike },
{ "vi-overstrike-delete", rl_vi_overstrike_delete },
{ "vi-prev-word", rl_vi_prev_word },
{ "vi-put", rl_vi_put },
{ "vi-redo", rl_vi_redo },
{ "vi-replace", rl_vi_replace },
{ "vi-rubout", rl_vi_rubout },
{ "vi-search", rl_vi_search },
{ "vi-search-again", rl_vi_search_again },
{ "vi-set-mark", rl_vi_set_mark },
{ "vi-subst", rl_vi_subst },
{ "vi-tilde-expand", rl_vi_tilde_expand },
{ "vi-yank-arg", rl_vi_yank_arg },
{ "vi-yank-to", rl_vi_yank_to },
#endif /* VI_MODE */
{(char *)NULL, (rl_command_func_t *)NULL }
};
int
rl_add_funmap_entry (name, function)
const char *name;
rl_command_func_t *function;
{
if (funmap_entry + 2 >= funmap_size)
{
funmap_size += 64;
funmap = (FUNMAP **)xrealloc (funmap, funmap_size * sizeof (FUNMAP *));
}
funmap[funmap_entry] = (FUNMAP *)xmalloc (sizeof (FUNMAP));
funmap[funmap_entry]->name = name;
funmap[funmap_entry]->function = function;
funmap[++funmap_entry] = (FUNMAP *)NULL;
return funmap_entry;
}
static int funmap_initialized;
/* Make the funmap contain all of the default entries. */
void
rl_initialize_funmap ()
{
register int i;
if (funmap_initialized)
return;
for (i = 0; default_funmap[i].name; i++)
rl_add_funmap_entry (default_funmap[i].name, default_funmap[i].function);
funmap_initialized = 1;
funmap_program_specific_entry_start = i;
}
/* Produce a NULL terminated array of known function names. The array
is sorted. The array itself is allocated, but not the strings inside.
You should free () the array when you done, but not the pointrs. */
const char **
rl_funmap_names ()
{
const char **result;
int result_size, result_index;
/* Make sure that the function map has been initialized. */
rl_initialize_funmap ();
for (result_index = result_size = 0, result = (const char **)NULL; funmap[result_index]; result_index++)
{
if (result_index + 2 > result_size)
{
result_size += 20;
result = (const char **)xrealloc (result, result_size * sizeof (char *));
}
result[result_index] = funmap[result_index]->name;
result[result_index + 1] = (char *)NULL;
}
qsort (result, result_index, sizeof (char *), (QSFUNC *)_rl_qsort_string_compare);
return (result);
}
+2 -9
View File
@@ -125,14 +125,7 @@ history_filename (filename)
home = sh_get_env_value ("HOME");
if (home == 0)
{
#if 0
home = ".";
home_len = 1;
#else
return (NULL);
#endif
}
return (NULL);
else
home_len = strlen (home);
@@ -430,7 +423,7 @@ history_do_write (filename, nelements, overwrite)
int nelements, overwrite;
{
register int i;
char *output;
char *output, *bakname;
int file, mode, rv;
#ifdef HISTORY_USE_MMAP
size_t cursize;
+552
View File
@@ -0,0 +1,552 @@
/* histfile.c - functions to manipulate the history file. */
/* Copyright (C) 1989-2010 Free Software Foundation, Inc.
This file contains the GNU History Library (History), a set of
routines for managing the text of previously typed lines.
History 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.
History 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 History. If not, see <http://www.gnu.org/licenses/>.
*/
/* The goal is to make the implementation transparent, so that you
don't have to know what data types are used, just what functions
you can call. I think I have done that. */
#define READLINE_LIBRARY
#if defined (__TANDEM)
# include <floss.h>
#endif
#if defined (HAVE_CONFIG_H)
# include <config.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#include "posixstat.h"
#include <fcntl.h>
#if defined (HAVE_STDLIB_H)
# include <stdlib.h>
#else
# include "ansi_stdlib.h"
#endif /* HAVE_STDLIB_H */
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <ctype.h>
#if defined (__EMX__)
# undef HAVE_MMAP
#endif
#ifdef HISTORY_USE_MMAP
# include <sys/mman.h>
# ifdef MAP_FILE
# define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE)
# define MAP_WFLAGS (MAP_FILE|MAP_SHARED)
# else
# define MAP_RFLAGS MAP_PRIVATE
# define MAP_WFLAGS MAP_SHARED
# endif
# ifndef MAP_FAILED
# define MAP_FAILED ((void *)-1)
# endif
#endif /* HISTORY_USE_MMAP */
/* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment
on win 95/98/nt), we want to open files with O_BINARY mode so that there
is no \n -> \r\n conversion performed. On other systems, we don't want to
mess around with O_BINARY at all, so we ensure that it's defined to 0. */
#if defined (__EMX__) || defined (__CYGWIN__)
# ifndef O_BINARY
# define O_BINARY 0
# endif
#else /* !__EMX__ && !__CYGWIN__ */
# undef O_BINARY
# define O_BINARY 0
#endif /* !__EMX__ && !__CYGWIN__ */
#include <errno.h>
#if !defined (errno)
extern int errno;
#endif /* !errno */
#include "history.h"
#include "histlib.h"
#include "rlshell.h"
#include "xmalloc.h"
/* If non-zero, we write timestamps to the history file in history_do_write() */
int history_write_timestamps = 0;
/* Does S look like the beginning of a history timestamp entry? Placeholder
for more extensive tests. */
#define HIST_TIMESTAMP_START(s) (*(s) == history_comment_char && isdigit ((s)[1]) )
/* Return the string that should be used in the place of this
filename. This only matters when you don't specify the
filename to read_history (), or write_history (). */
static char *
history_filename (filename)
const char *filename;
{
char *return_val;
const char *home;
int home_len;
return_val = filename ? savestring (filename) : (char *)NULL;
if (return_val)
return (return_val);
home = sh_get_env_value ("HOME");
if (home == 0)
{
#if 0
home = ".";
home_len = 1;
#else
return (NULL);
#endif
}
else
home_len = strlen (home);
return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
strcpy (return_val, home);
return_val[home_len] = '/';
#if defined (__MSDOS__)
strcpy (return_val + home_len + 1, "_history");
#else
strcpy (return_val + home_len + 1, ".history");
#endif
return (return_val);
}
/* Add the contents of FILENAME to the history list, a line at a time.
If FILENAME is NULL, then read from ~/.history. Returns 0 if
successful, or errno if not. */
int
read_history (filename)
const char *filename;
{
return (read_history_range (filename, 0, -1));
}
/* Read a range of lines from FILENAME, adding them to the history list.
Start reading at the FROM'th line and end at the TO'th. If FROM
is zero, start at the beginning. If TO is less than FROM, read
until the end of the file. If FILENAME is NULL, then read from
~/.history. Returns 0 if successful, or errno if not. */
int
read_history_range (filename, from, to)
const char *filename;
int from, to;
{
register char *line_start, *line_end, *p;
char *input, *buffer, *bufend, *last_ts;
int file, current_line, chars_read;
struct stat finfo;
size_t file_size;
#if defined (EFBIG)
int overflow_errno = EFBIG;
#elif defined (EOVERFLOW)
int overflow_errno = EOVERFLOW;
#else
int overflow_errno = EIO;
#endif
buffer = last_ts = (char *)NULL;
input = history_filename (filename);
file = input ? open (input, O_RDONLY|O_BINARY, 0666) : -1;
if ((file < 0) || (fstat (file, &finfo) == -1))
goto error_and_exit;
file_size = (size_t)finfo.st_size;
/* check for overflow on very large files */
if (file_size != finfo.st_size || file_size + 1 < file_size)
{
errno = overflow_errno;
goto error_and_exit;
}
#ifdef HISTORY_USE_MMAP
/* We map read/write and private so we can change newlines to NULs without
affecting the underlying object. */
buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0);
if ((void *)buffer == MAP_FAILED)
{
errno = overflow_errno;
goto error_and_exit;
}
chars_read = file_size;
#else
buffer = (char *)malloc (file_size + 1);
if (buffer == 0)
{
errno = overflow_errno;
goto error_and_exit;
}
chars_read = read (file, buffer, file_size);
#endif
if (chars_read < 0)
{
error_and_exit:
if (errno != 0)
chars_read = errno;
else
chars_read = EIO;
if (file >= 0)
close (file);
FREE (input);
#ifndef HISTORY_USE_MMAP
FREE (buffer);
#endif
return (chars_read);
}
close (file);
/* Set TO to larger than end of file if negative. */
if (to < 0)
to = chars_read;
/* Start at beginning of file, work to end. */
bufend = buffer + chars_read;
current_line = 0;
/* Skip lines until we are at FROM. */
for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
if (*line_end == '\n')
{
p = line_end + 1;
/* If we see something we think is a timestamp, continue with this
line. We should check more extensively here... */
if (HIST_TIMESTAMP_START(p) == 0)
current_line++;
line_start = p;
}
/* If there are lines left to gobble, then gobble them now. */
for (line_end = line_start; line_end < bufend; line_end++)
if (*line_end == '\n')
{
/* Change to allow Windows-like \r\n end of line delimiter. */
if (line_end > line_start && line_end[-1] == '\r')
line_end[-1] = '\0';
else
*line_end = '\0';
if (*line_start)
{
if (HIST_TIMESTAMP_START(line_start) == 0)
{
add_history (line_start);
if (last_ts)
{
add_history_time (last_ts);
last_ts = NULL;
}
}
else
{
last_ts = line_start;
current_line--;
}
}
current_line++;
if (current_line >= to)
break;
line_start = line_end + 1;
}
FREE (input);
#ifndef HISTORY_USE_MMAP
FREE (buffer);
#else
munmap (buffer, file_size);
#endif
return (0);
}
/* Truncate the history file FNAME, leaving only LINES trailing lines.
If FNAME is NULL, then use ~/.history. Returns 0 on success, errno
on failure. */
int
history_truncate_file (fname, lines)
const char *fname;
int lines;
{
char *buffer, *filename, *bp, *bp1; /* bp1 == bp+1 */
int file, chars_read, rv;
struct stat finfo;
size_t file_size;
buffer = (char *)NULL;
filename = history_filename (fname);
file = filename ? open (filename, O_RDONLY|O_BINARY, 0666) : -1;
rv = 0;
/* Don't try to truncate non-regular files. */
if (file == -1 || fstat (file, &finfo) == -1)
{
rv = errno;
if (file != -1)
close (file);
goto truncate_exit;
}
if (S_ISREG (finfo.st_mode) == 0)
{
close (file);
#ifdef EFTYPE
rv = EFTYPE;
#else
rv = EINVAL;
#endif
goto truncate_exit;
}
file_size = (size_t)finfo.st_size;
/* check for overflow on very large files */
if (file_size != finfo.st_size || file_size + 1 < file_size)
{
close (file);
#if defined (EFBIG)
rv = errno = EFBIG;
#elif defined (EOVERFLOW)
rv = errno = EOVERFLOW;
#else
rv = errno = EINVAL;
#endif
goto truncate_exit;
}
buffer = (char *)malloc (file_size + 1);
if (buffer == 0)
{
close (file);
goto truncate_exit;
}
chars_read = read (file, buffer, file_size);
close (file);
if (chars_read <= 0)
{
rv = (chars_read < 0) ? errno : 0;
goto truncate_exit;
}
/* Count backwards from the end of buffer until we have passed
LINES lines. bp1 is set funny initially. But since bp[1] can't
be a comment character (since it's off the end) and *bp can't be
both a newline and the history comment character, it should be OK. */
for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
{
if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
lines--;
bp1 = bp;
}
/* If this is the first line, then the file contains exactly the
number of lines we want to truncate to, so we don't need to do
anything. It's the first line if we don't find a newline between
the current value of i and 0. Otherwise, write from the start of
this line until the end of the buffer. */
for ( ; bp > buffer; bp--)
{
if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
{
bp++;
break;
}
bp1 = bp;
}
/* Write only if there are more lines in the file than we want to
truncate to. */
if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
{
write (file, bp, chars_read - (bp - buffer));
#if defined (__BEOS__)
/* BeOS ignores O_TRUNC. */
ftruncate (file, chars_read - (bp - buffer));
#endif
close (file);
}
truncate_exit:
FREE (buffer);
xfree (filename);
return rv;
}
/* Workhorse function for writing history. Writes NELEMENT entries
from the history list to FILENAME. OVERWRITE is non-zero if you
wish to replace FILENAME with the entries. */
static int
history_do_write (filename, nelements, overwrite)
const char *filename;
int nelements, overwrite;
{
register int i;
char *output;
int file, mode, rv;
#ifdef HISTORY_USE_MMAP
size_t cursize;
mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
#else
mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
#endif
output = history_filename (filename);
file = output ? open (output, mode, 0600) : -1;
rv = 0;
if (file == -1)
{
FREE (output);
return (errno);
}
#ifdef HISTORY_USE_MMAP
cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
#endif
if (nelements > history_length)
nelements = history_length;
/* Build a buffer of all the lines to write, and write them in one syscall.
Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
{
HIST_ENTRY **the_history; /* local */
register int j;
int buffer_size;
char *buffer;
the_history = history_list ();
/* Calculate the total number of bytes to write. */
for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
#if 0
buffer_size += 2 + HISTENT_BYTES (the_history[i]);
#else
{
if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
buffer_size += strlen (the_history[i]->timestamp) + 1;
buffer_size += strlen (the_history[i]->line) + 1;
}
#endif
/* Allocate the buffer, and fill it. */
#ifdef HISTORY_USE_MMAP
if (ftruncate (file, buffer_size+cursize) == -1)
goto mmap_error;
buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);
if ((void *)buffer == MAP_FAILED)
{
mmap_error:
rv = errno;
FREE (output);
close (file);
return rv;
}
#else
buffer = (char *)malloc (buffer_size);
if (buffer == 0)
{
rv = errno;
FREE (output);
close (file);
return rv;
}
#endif
for (j = 0, i = history_length - nelements; i < history_length; i++)
{
if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
{
strcpy (buffer + j, the_history[i]->timestamp);
j += strlen (the_history[i]->timestamp);
buffer[j++] = '\n';
}
strcpy (buffer + j, the_history[i]->line);
j += strlen (the_history[i]->line);
buffer[j++] = '\n';
}
#ifdef HISTORY_USE_MMAP
if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0)
rv = errno;
#else
if (write (file, buffer, buffer_size) < 0)
rv = errno;
xfree (buffer);
#endif
}
close (file);
FREE (output);
return (rv);
}
/* Append NELEMENT entries to FILENAME. The entries appended are from
the end of the list minus NELEMENTs up to the end of the list. */
int
append_history (nelements, filename)
int nelements;
const char *filename;
{
return (history_do_write (filename, nelements, HISTORY_APPEND));
}
/* Overwrite FILENAME with the current history. If FILENAME is NULL,
then write the history list to ~/.history. Values returned
are as in read_history ().*/
int
write_history (filename)
const char *filename;
{
return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
}
+2
View File
@@ -204,6 +204,8 @@ extern int rl_tty_status PARAMS((int, int));
/* Bindable commands for incremental and non-incremental history searching. */
extern int rl_history_search_forward PARAMS((int, int));
extern int rl_history_search_backward PARAMS((int, int));
extern int rl_history_substr_search_forward PARAMS((int, int));
extern int rl_history_substr_search_backward PARAMS((int, int));
extern int rl_noninc_forward_search PARAMS((int, int));
extern int rl_noninc_reverse_search PARAMS((int, int));
extern int rl_noninc_forward_search_again PARAMS((int, int));
+893
View File
@@ -0,0 +1,893 @@
/* Readline.h -- the names of functions callable from within readline. */
/* Copyright (C) 1987-2011 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/>.
*/
#if !defined (_READLINE_H_)
#define _READLINE_H_
#ifdef __cplusplus
extern "C" {
#endif
#if defined (READLINE_LIBRARY)
# include "rlstdc.h"
# include "rltypedefs.h"
# include "keymaps.h"
# include "tilde.h"
#else
# include <readline/rlstdc.h>
# include <readline/rltypedefs.h>
# include <readline/keymaps.h>
# include <readline/tilde.h>
#endif
/* Hex-encoded Readline version number. */
#define RL_READLINE_VERSION 0x0602 /* Readline 6.2 */
#define RL_VERSION_MAJOR 6
#define RL_VERSION_MINOR 2
/* Readline data structures. */
/* Maintaining the state of undo. We remember individual deletes and inserts
on a chain of things to do. */
/* The actions that undo knows how to undo. Notice that UNDO_DELETE means
to insert some text, and UNDO_INSERT means to delete some text. I.e.,
the code tells undo what to undo, not how to undo it. */
enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END };
/* What an element of THE_UNDO_LIST looks like. */
typedef struct undo_list {
struct undo_list *next;
int start, end; /* Where the change took place. */
char *text; /* The text to insert, if undoing a delete. */
enum undo_code what; /* Delete, Insert, Begin, End. */
} UNDO_LIST;
/* The current undo list for RL_LINE_BUFFER. */
extern UNDO_LIST *rl_undo_list;
/* The data structure for mapping textual names to code addresses. */
typedef struct _funmap {
const char *name;
rl_command_func_t *function;
} FUNMAP;
extern FUNMAP **funmap;
/* **************************************************************** */
/* */
/* Functions available to bind to key sequences */
/* */
/* **************************************************************** */
/* Bindable commands for numeric arguments. */
extern int rl_digit_argument PARAMS((int, int));
extern int rl_universal_argument PARAMS((int, int));
/* Bindable commands for moving the cursor. */
extern int rl_forward_byte PARAMS((int, int));
extern int rl_forward_char PARAMS((int, int));
extern int rl_forward PARAMS((int, int));
extern int rl_backward_byte PARAMS((int, int));
extern int rl_backward_char PARAMS((int, int));
extern int rl_backward PARAMS((int, int));
extern int rl_beg_of_line PARAMS((int, int));
extern int rl_end_of_line PARAMS((int, int));
extern int rl_forward_word PARAMS((int, int));
extern int rl_backward_word PARAMS((int, int));
extern int rl_refresh_line PARAMS((int, int));
extern int rl_clear_screen PARAMS((int, int));
extern int rl_skip_csi_sequence PARAMS((int, int));
extern int rl_arrow_keys PARAMS((int, int));
/* Bindable commands for inserting and deleting text. */
extern int rl_insert PARAMS((int, int));
extern int rl_quoted_insert PARAMS((int, int));
extern int rl_tab_insert PARAMS((int, int));
extern int rl_newline PARAMS((int, int));
extern int rl_do_lowercase_version PARAMS((int, int));
extern int rl_rubout PARAMS((int, int));
extern int rl_delete PARAMS((int, int));
extern int rl_rubout_or_delete PARAMS((int, int));
extern int rl_delete_horizontal_space PARAMS((int, int));
extern int rl_delete_or_show_completions PARAMS((int, int));
extern int rl_insert_comment PARAMS((int, int));
/* Bindable commands for changing case. */
extern int rl_upcase_word PARAMS((int, int));
extern int rl_downcase_word PARAMS((int, int));
extern int rl_capitalize_word PARAMS((int, int));
/* Bindable commands for transposing characters and words. */
extern int rl_transpose_words PARAMS((int, int));
extern int rl_transpose_chars PARAMS((int, int));
/* Bindable commands for searching within a line. */
extern int rl_char_search PARAMS((int, int));
extern int rl_backward_char_search PARAMS((int, int));
/* Bindable commands for readline's interface to the command history. */
extern int rl_beginning_of_history PARAMS((int, int));
extern int rl_end_of_history PARAMS((int, int));
extern int rl_get_next_history PARAMS((int, int));
extern int rl_get_previous_history PARAMS((int, int));
/* Bindable commands for managing the mark and region. */
extern int rl_set_mark PARAMS((int, int));
extern int rl_exchange_point_and_mark PARAMS((int, int));
/* Bindable commands to set the editing mode (emacs or vi). */
extern int rl_vi_editing_mode PARAMS((int, int));
extern int rl_emacs_editing_mode PARAMS((int, int));
/* Bindable commands to change the insert mode (insert or overwrite) */
extern int rl_overwrite_mode PARAMS((int, int));
/* Bindable commands for managing key bindings. */
extern int rl_re_read_init_file PARAMS((int, int));
extern int rl_dump_functions PARAMS((int, int));
extern int rl_dump_macros PARAMS((int, int));
extern int rl_dump_variables PARAMS((int, int));
/* Bindable commands for word completion. */
extern int rl_complete PARAMS((int, int));
extern int rl_possible_completions PARAMS((int, int));
extern int rl_insert_completions PARAMS((int, int));
extern int rl_old_menu_complete PARAMS((int, int));
extern int rl_menu_complete PARAMS((int, int));
extern int rl_backward_menu_complete PARAMS((int, int));
/* Bindable commands for killing and yanking text, and managing the kill ring. */
extern int rl_kill_word PARAMS((int, int));
extern int rl_backward_kill_word PARAMS((int, int));
extern int rl_kill_line PARAMS((int, int));
extern int rl_backward_kill_line PARAMS((int, int));
extern int rl_kill_full_line PARAMS((int, int));
extern int rl_unix_word_rubout PARAMS((int, int));
extern int rl_unix_filename_rubout PARAMS((int, int));
extern int rl_unix_line_discard PARAMS((int, int));
extern int rl_copy_region_to_kill PARAMS((int, int));
extern int rl_kill_region PARAMS((int, int));
extern int rl_copy_forward_word PARAMS((int, int));
extern int rl_copy_backward_word PARAMS((int, int));
extern int rl_yank PARAMS((int, int));
extern int rl_yank_pop PARAMS((int, int));
extern int rl_yank_nth_arg PARAMS((int, int));
extern int rl_yank_last_arg PARAMS((int, int));
/* Not available unless __CYGWIN__ is defined. */
#ifdef __CYGWIN__
extern int rl_paste_from_clipboard PARAMS((int, int));
#endif
/* Bindable commands for incremental searching. */
extern int rl_reverse_search_history PARAMS((int, int));
extern int rl_forward_search_history PARAMS((int, int));
/* Bindable keyboard macro commands. */
extern int rl_start_kbd_macro PARAMS((int, int));
extern int rl_end_kbd_macro PARAMS((int, int));
extern int rl_call_last_kbd_macro PARAMS((int, int));
/* Bindable undo commands. */
extern int rl_revert_line PARAMS((int, int));
extern int rl_undo_command PARAMS((int, int));
/* Bindable tilde expansion commands. */
extern int rl_tilde_expand PARAMS((int, int));
/* Bindable terminal control commands. */
extern int rl_restart_output PARAMS((int, int));
extern int rl_stop_output PARAMS((int, int));
/* Miscellaneous bindable commands. */
extern int rl_abort PARAMS((int, int));
extern int rl_tty_status PARAMS((int, int));
/* Bindable commands for incremental and non-incremental history searching. */
extern int rl_history_search_forward PARAMS((int, int));
extern int rl_history_search_backward PARAMS((int, int));
extern int rl_noninc_forward_search PARAMS((int, int));
extern int rl_noninc_reverse_search PARAMS((int, int));
extern int rl_noninc_forward_search_again PARAMS((int, int));
extern int rl_noninc_reverse_search_again PARAMS((int, int));
/* Bindable command used when inserting a matching close character. */
extern int rl_insert_close PARAMS((int, int));
/* Not available unless READLINE_CALLBACKS is defined. */
extern void rl_callback_handler_install PARAMS((const char *, rl_vcpfunc_t *));
extern void rl_callback_read_char PARAMS((void));
extern void rl_callback_handler_remove PARAMS((void));
/* Things for vi mode. Not available unless readline is compiled -DVI_MODE. */
/* VI-mode bindable commands. */
extern int rl_vi_redo PARAMS((int, int));
extern int rl_vi_undo PARAMS((int, int));
extern int rl_vi_yank_arg PARAMS((int, int));
extern int rl_vi_fetch_history PARAMS((int, int));
extern int rl_vi_search_again PARAMS((int, int));
extern int rl_vi_search PARAMS((int, int));
extern int rl_vi_complete PARAMS((int, int));
extern int rl_vi_tilde_expand PARAMS((int, int));
extern int rl_vi_prev_word PARAMS((int, int));
extern int rl_vi_next_word PARAMS((int, int));
extern int rl_vi_end_word PARAMS((int, int));
extern int rl_vi_insert_beg PARAMS((int, int));
extern int rl_vi_append_mode PARAMS((int, int));
extern int rl_vi_append_eol PARAMS((int, int));
extern int rl_vi_eof_maybe PARAMS((int, int));
extern int rl_vi_insertion_mode PARAMS((int, int));
extern int rl_vi_insert_mode PARAMS((int, int));
extern int rl_vi_movement_mode PARAMS((int, int));
extern int rl_vi_arg_digit PARAMS((int, int));
extern int rl_vi_change_case PARAMS((int, int));
extern int rl_vi_put PARAMS((int, int));
extern int rl_vi_column PARAMS((int, int));
extern int rl_vi_delete_to PARAMS((int, int));
extern int rl_vi_change_to PARAMS((int, int));
extern int rl_vi_yank_to PARAMS((int, int));
extern int rl_vi_rubout PARAMS((int, int));
extern int rl_vi_delete PARAMS((int, int));
extern int rl_vi_back_to_indent PARAMS((int, int));
extern int rl_vi_first_print PARAMS((int, int));
extern int rl_vi_char_search PARAMS((int, int));
extern int rl_vi_match PARAMS((int, int));
extern int rl_vi_change_char PARAMS((int, int));
extern int rl_vi_subst PARAMS((int, int));
extern int rl_vi_overstrike PARAMS((int, int));
extern int rl_vi_overstrike_delete PARAMS((int, int));
extern int rl_vi_replace PARAMS((int, int));
extern int rl_vi_set_mark PARAMS((int, int));
extern int rl_vi_goto_mark PARAMS((int, int));
/* VI-mode utility functions. */
extern int rl_vi_check PARAMS((void));
extern int rl_vi_domove PARAMS((int, int *));
extern int rl_vi_bracktype PARAMS((int));
extern void rl_vi_start_inserting PARAMS((int, int, int));
/* VI-mode pseudo-bindable commands, used as utility functions. */
extern int rl_vi_fWord PARAMS((int, int));
extern int rl_vi_bWord PARAMS((int, int));
extern int rl_vi_eWord PARAMS((int, int));
extern int rl_vi_fword PARAMS((int, int));
extern int rl_vi_bword PARAMS((int, int));
extern int rl_vi_eword PARAMS((int, int));
/* **************************************************************** */
/* */
/* Well Published Functions */
/* */
/* **************************************************************** */
/* Readline functions. */
/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. */
extern char *readline PARAMS((const char *));
extern int rl_set_prompt PARAMS((const char *));
extern int rl_expand_prompt PARAMS((char *));
extern int rl_initialize PARAMS((void));
/* Undocumented; unused by readline */
extern int rl_discard_argument PARAMS((void));
/* Utility functions to bind keys to readline commands. */
extern int rl_add_defun PARAMS((const char *, rl_command_func_t *, int));
extern int rl_bind_key PARAMS((int, rl_command_func_t *));
extern int rl_bind_key_in_map PARAMS((int, rl_command_func_t *, Keymap));
extern int rl_unbind_key PARAMS((int));
extern int rl_unbind_key_in_map PARAMS((int, Keymap));
extern int rl_bind_key_if_unbound PARAMS((int, rl_command_func_t *));
extern int rl_bind_key_if_unbound_in_map PARAMS((int, rl_command_func_t *, Keymap));
extern int rl_unbind_function_in_map PARAMS((rl_command_func_t *, Keymap));
extern int rl_unbind_command_in_map PARAMS((const char *, Keymap));
extern int rl_bind_keyseq PARAMS((const char *, rl_command_func_t *));
extern int rl_bind_keyseq_in_map PARAMS((const char *, rl_command_func_t *, Keymap));
extern int rl_bind_keyseq_if_unbound PARAMS((const char *, rl_command_func_t *));
extern int rl_bind_keyseq_if_unbound_in_map PARAMS((const char *, rl_command_func_t *, Keymap));
extern int rl_generic_bind PARAMS((int, const char *, char *, Keymap));
extern char *rl_variable_value PARAMS((const char *));
extern int rl_variable_bind PARAMS((const char *, const char *));
/* Backwards compatibility, use rl_bind_keyseq_in_map instead. */
extern int rl_set_key PARAMS((const char *, rl_command_func_t *, Keymap));
/* Backwards compatibility, use rl_generic_bind instead. */
extern int rl_macro_bind PARAMS((const char *, const char *, Keymap));
/* Undocumented in the texinfo manual; not really useful to programs. */
extern int rl_translate_keyseq PARAMS((const char *, char *, int *));
extern char *rl_untranslate_keyseq PARAMS((int));
extern rl_command_func_t *rl_named_function PARAMS((const char *));
extern rl_command_func_t *rl_function_of_keyseq PARAMS((const char *, Keymap, int *));
extern void rl_list_funmap_names PARAMS((void));
extern char **rl_invoking_keyseqs_in_map PARAMS((rl_command_func_t *, Keymap));
extern char **rl_invoking_keyseqs PARAMS((rl_command_func_t *));
extern void rl_function_dumper PARAMS((int));
extern void rl_macro_dumper PARAMS((int));
extern void rl_variable_dumper PARAMS((int));
extern int rl_read_init_file PARAMS((const char *));
extern int rl_parse_and_bind PARAMS((char *));
/* Functions for manipulating keymaps. */
extern Keymap rl_make_bare_keymap PARAMS((void));
extern Keymap rl_copy_keymap PARAMS((Keymap));
extern Keymap rl_make_keymap PARAMS((void));
extern void rl_discard_keymap PARAMS((Keymap));
extern Keymap rl_get_keymap_by_name PARAMS((const char *));
extern char *rl_get_keymap_name PARAMS((Keymap));
extern void rl_set_keymap PARAMS((Keymap));
extern Keymap rl_get_keymap PARAMS((void));
/* Undocumented; used internally only. */
extern void rl_set_keymap_from_edit_mode PARAMS((void));
extern char *rl_get_keymap_name_from_edit_mode PARAMS((void));
/* Functions for manipulating the funmap, which maps command names to functions. */
extern int rl_add_funmap_entry PARAMS((const char *, rl_command_func_t *));
extern const char **rl_funmap_names PARAMS((void));
/* Undocumented, only used internally -- there is only one funmap, and this
function may be called only once. */
extern void rl_initialize_funmap PARAMS((void));
/* Utility functions for managing keyboard macros. */
extern void rl_push_macro_input PARAMS((char *));
/* Functions for undoing, from undo.c */
extern void rl_add_undo PARAMS((enum undo_code, int, int, char *));
extern void rl_free_undo_list PARAMS((void));
extern int rl_do_undo PARAMS((void));
extern int rl_begin_undo_group PARAMS((void));
extern int rl_end_undo_group PARAMS((void));
extern int rl_modifying PARAMS((int, int));
/* Functions for redisplay. */
extern void rl_redisplay PARAMS((void));
extern int rl_on_new_line PARAMS((void));
extern int rl_on_new_line_with_prompt PARAMS((void));
extern int rl_forced_update_display PARAMS((void));
extern int rl_clear_message PARAMS((void));
extern int rl_reset_line_state PARAMS((void));
extern int rl_crlf PARAMS((void));
#if defined (USE_VARARGS) && defined (PREFER_STDARG)
extern int rl_message (const char *, ...) __attribute__((__format__ (printf, 1, 2)));
#else
extern int rl_message ();
#endif
extern int rl_show_char PARAMS((int));
/* Undocumented in texinfo manual. */
extern int rl_character_len PARAMS((int, int));
/* Save and restore internal prompt redisplay information. */
extern void rl_save_prompt PARAMS((void));
extern void rl_restore_prompt PARAMS((void));
/* Modifying text. */
extern void rl_replace_line PARAMS((const char *, int));
extern int rl_insert_text PARAMS((const char *));
extern int rl_delete_text PARAMS((int, int));
extern int rl_kill_text PARAMS((int, int));
extern char *rl_copy_text PARAMS((int, int));
/* Terminal and tty mode management. */
extern void rl_prep_terminal PARAMS((int));
extern void rl_deprep_terminal PARAMS((void));
extern void rl_tty_set_default_bindings PARAMS((Keymap));
extern void rl_tty_unset_default_bindings PARAMS((Keymap));
extern int rl_reset_terminal PARAMS((const char *));
extern void rl_resize_terminal PARAMS((void));
extern void rl_set_screen_size PARAMS((int, int));
extern void rl_get_screen_size PARAMS((int *, int *));
extern void rl_reset_screen_size PARAMS((void));
extern char *rl_get_termcap PARAMS((const char *));
/* Functions for character input. */
extern int rl_stuff_char PARAMS((int));
extern int rl_execute_next PARAMS((int));
extern int rl_clear_pending_input PARAMS((void));
extern int rl_read_key PARAMS((void));
extern int rl_getc PARAMS((FILE *));
extern int rl_set_keyboard_input_timeout PARAMS((int));
/* `Public' utility functions . */
extern void rl_extend_line_buffer PARAMS((int));
extern int rl_ding PARAMS((void));
extern int rl_alphabetic PARAMS((int));
extern void rl_free PARAMS((void *));
/* Readline signal handling, from signals.c */
extern int rl_set_signals PARAMS((void));
extern int rl_clear_signals PARAMS((void));
extern void rl_cleanup_after_signal PARAMS((void));
extern void rl_reset_after_signal PARAMS((void));
extern void rl_free_line_state PARAMS((void));
extern void rl_echo_signal_char PARAMS((int));
extern int rl_set_paren_blink_timeout PARAMS((int));
/* Undocumented. */
extern int rl_maybe_save_line PARAMS((void));
extern int rl_maybe_unsave_line PARAMS((void));
extern int rl_maybe_replace_line PARAMS((void));
/* Completion functions. */
extern int rl_complete_internal PARAMS((int));
extern void rl_display_match_list PARAMS((char **, int, int));
extern char **rl_completion_matches PARAMS((const char *, rl_compentry_func_t *));
extern char *rl_username_completion_function PARAMS((const char *, int));
extern char *rl_filename_completion_function PARAMS((const char *, int));
extern int rl_completion_mode PARAMS((rl_command_func_t *));
#if 0
/* Backwards compatibility (compat.c). These will go away sometime. */
extern void free_undo_list PARAMS((void));
extern int maybe_save_line PARAMS((void));
extern int maybe_unsave_line PARAMS((void));
extern int maybe_replace_line PARAMS((void));
extern int ding PARAMS((void));
extern int alphabetic PARAMS((int));
extern int crlf PARAMS((void));
extern char **completion_matches PARAMS((char *, rl_compentry_func_t *));
extern char *username_completion_function PARAMS((const char *, int));
extern char *filename_completion_function PARAMS((const char *, int));
#endif
/* **************************************************************** */
/* */
/* Well Published Variables */
/* */
/* **************************************************************** */
/* The version of this incarnation of the readline library. */
extern const char *rl_library_version; /* e.g., "4.2" */
extern int rl_readline_version; /* e.g., 0x0402 */
/* True if this is real GNU readline. */
extern int rl_gnu_readline_p;
/* Flags word encapsulating the current readline state. */
extern int rl_readline_state;
/* Says which editing mode readline is currently using. 1 means emacs mode;
0 means vi mode. */
extern int rl_editing_mode;
/* Insert or overwrite mode for emacs mode. 1 means insert mode; 0 means
overwrite mode. Reset to insert mode on each input line. */
extern int rl_insert_mode;
/* The name of the calling program. You should initialize this to
whatever was in argv[0]. It is used when parsing conditionals. */
extern const char *rl_readline_name;
/* The prompt readline uses. This is set from the argument to
readline (), and should not be assigned to directly. */
extern char *rl_prompt;
/* The prompt string that is actually displayed by rl_redisplay. Public so
applications can more easily supply their own redisplay functions. */
extern char *rl_display_prompt;
/* The line buffer that is in use. */
extern char *rl_line_buffer;
/* The location of point, and end. */
extern int rl_point;
extern int rl_end;
/* The mark, or saved cursor position. */
extern int rl_mark;
/* Flag to indicate that readline has finished with the current input
line and should return it. */
extern int rl_done;
/* If set to a character value, that will be the next keystroke read. */
extern int rl_pending_input;
/* Non-zero if we called this function from _rl_dispatch(). It's present
so functions can find out whether they were called from a key binding
or directly from an application. */
extern int rl_dispatching;
/* Non-zero if the user typed a numeric argument before executing the
current function. */
extern int rl_explicit_arg;
/* The current value of the numeric argument specified by the user. */
extern int rl_numeric_arg;
/* The address of the last command function Readline executed. */
extern rl_command_func_t *rl_last_func;
/* The name of the terminal to use. */
extern const char *rl_terminal_name;
/* The input and output streams. */
extern FILE *rl_instream;
extern FILE *rl_outstream;
/* If non-zero, Readline gives values of LINES and COLUMNS from the environment
greater precedence than values fetched from the kernel when computing the
screen dimensions. */
extern int rl_prefer_env_winsize;
/* If non-zero, then this is the address of a function to call just
before readline_internal () prints the first prompt. */
extern rl_hook_func_t *rl_startup_hook;
/* If non-zero, this is the address of a function to call just before
readline_internal_setup () returns and readline_internal starts
reading input characters. */
extern rl_hook_func_t *rl_pre_input_hook;
/* The address of a function to call periodically while Readline is
awaiting character input, or NULL, for no event handling. */
extern rl_hook_func_t *rl_event_hook;
/* The address of the function to call to fetch a character from the current
Readline input stream */
extern rl_getc_func_t *rl_getc_function;
extern rl_voidfunc_t *rl_redisplay_function;
extern rl_vintfunc_t *rl_prep_term_function;
extern rl_voidfunc_t *rl_deprep_term_function;
/* Dispatch variables. */
extern Keymap rl_executing_keymap;
extern Keymap rl_binding_keymap;
/* Display variables. */
/* If non-zero, readline will erase the entire line, including any prompt,
if the only thing typed on an otherwise-blank line is something bound to
rl_newline. */
extern int rl_erase_empty_line;
/* If non-zero, the application has already printed the prompt (rl_prompt)
before calling readline, so readline should not output it the first time
redisplay is done. */
extern int rl_already_prompted;
/* A non-zero value means to read only this many characters rather than
up to a character bound to accept-line. */
extern int rl_num_chars_to_read;
/* The text of a currently-executing keyboard macro. */
extern char *rl_executing_macro;
/* Variables to control readline signal handling. */
/* If non-zero, readline will install its own signal handlers for
SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */
extern int rl_catch_signals;
/* If non-zero, readline will install a signal handler for SIGWINCH
that also attempts to call any calling application's SIGWINCH signal
handler. Note that the terminal is not cleaned up before the
application's signal handler is called; use rl_cleanup_after_signal()
to do that. */
extern int rl_catch_sigwinch;
/* Completion variables. */
/* Pointer to the generator function for completion_matches ().
NULL means to use rl_filename_completion_function (), the default
filename completer. */
extern rl_compentry_func_t *rl_completion_entry_function;
/* Optional generator for menu completion. Default is
rl_completion_entry_function (rl_filename_completion_function). */
extern rl_compentry_func_t *rl_menu_completion_entry_function;
/* If rl_ignore_some_completions_function is non-NULL it is the address
of a function to call after all of the possible matches have been
generated, but before the actual completion is done to the input line.
The function is called with one argument; a NULL terminated array
of (char *). If your function removes any of the elements, they
must be free()'ed. */
extern rl_compignore_func_t *rl_ignore_some_completions_function;
/* Pointer to alternative function to create matches.
Function is called with TEXT, START, and END.
START and END are indices in RL_LINE_BUFFER saying what the boundaries
of TEXT are.
If this function exists and returns NULL then call the value of
rl_completion_entry_function to try to match, otherwise use the
array of strings returned. */
extern rl_completion_func_t *rl_attempted_completion_function;
/* The basic list of characters that signal a break between words for the
completer routine. The initial contents of this variable is what
breaks words in the shell, i.e. "n\"\\'`@$>". */
extern const char *rl_basic_word_break_characters;
/* The list of characters that signal a break between words for
rl_complete_internal. The default list is the contents of
rl_basic_word_break_characters. */
extern /*const*/ char *rl_completer_word_break_characters;
/* Hook function to allow an application to set the completion word
break characters before readline breaks up the line. Allows
position-dependent word break characters. */
extern rl_cpvfunc_t *rl_completion_word_break_hook;
/* List of characters which can be used to quote a substring of the line.
Completion occurs on the entire substring, and within the substring
rl_completer_word_break_characters are treated as any other character,
unless they also appear within this list. */
extern const char *rl_completer_quote_characters;
/* List of quote characters which cause a word break. */
extern const char *rl_basic_quote_characters;
/* List of characters that need to be quoted in filenames by the completer. */
extern const char *rl_filename_quote_characters;
/* List of characters that are word break characters, but should be left
in TEXT when it is passed to the completion function. The shell uses
this to help determine what kind of completing to do. */
extern const char *rl_special_prefixes;
/* If non-zero, then this is the address of a function to call when
completing on a directory name. The function is called with
the address of a string (the current directory name) as an arg. It
changes what is displayed when the possible completions are printed
or inserted. The directory completion hook should perform
any necessary dequoting. This function should return 1 if it modifies
the directory name pointer passed as an argument. If the directory
completion hook returns 0, it should not modify the directory name
pointer passed as an argument. */
extern rl_icppfunc_t *rl_directory_completion_hook;
/* If non-zero, this is the address of a function to call when completing
a directory name. This function takes the address of the directory name
to be modified as an argument. Unlike rl_directory_completion_hook, it
only modifies the directory name used in opendir(2), not what is displayed
when the possible completions are printed or inserted. If set, it takes
precedence over rl_directory_completion_hook. The directory rewrite
hook should perform any necessary dequoting. This function has the same
return value properties as the directory_completion_hook.
I'm not happy with how this works yet, so it's undocumented. I'm trying
it in bash to see how well it goes. */
extern rl_icppfunc_t *rl_directory_rewrite_hook;
/* If non-zero, this is the address of a function to call when reading
directory entries from the filesystem for completion and comparing
them to the partial word to be completed. The function should
either return its first argument (if no conversion takes place) or
newly-allocated memory. This can, for instance, convert filenames
between character sets for comparison against what's typed at the
keyboard. The returned value is what is added to the list of
matches. The second argument is the length of the filename to be
converted. */
extern rl_dequote_func_t *rl_filename_rewrite_hook;
/* Backwards compatibility with previous versions of readline. */
#define rl_symbolic_link_hook rl_directory_completion_hook
/* If non-zero, then this is the address of a function to call when
completing a word would normally display the list of possible matches.
This function is called instead of actually doing the display.
It takes three arguments: (char **matches, int num_matches, int max_length)
where MATCHES is the array of strings that matched, NUM_MATCHES is the
number of strings in that array, and MAX_LENGTH is the length of the
longest string in that array. */
extern rl_compdisp_func_t *rl_completion_display_matches_hook;
/* Non-zero means that the results of the matches are to be treated
as filenames. This is ALWAYS zero on entry, and can only be changed
within a completion entry finder function. */
extern int rl_filename_completion_desired;
/* Non-zero means that the results of the matches are to be quoted using
double quotes (or an application-specific quoting mechanism) if the
filename contains any characters in rl_word_break_chars. This is
ALWAYS non-zero on entry, and can only be changed within a completion
entry finder function. */
extern int rl_filename_quoting_desired;
/* Set to a function to quote a filename in an application-specific fashion.
Called with the text to quote, the type of match found (single or multiple)
and a pointer to the quoting character to be used, which the function can
reset if desired. */
extern rl_quote_func_t *rl_filename_quoting_function;
/* Function to call to remove quoting characters from a filename. Called
before completion is attempted, so the embedded quotes do not interfere
with matching names in the file system. */
extern rl_dequote_func_t *rl_filename_dequoting_function;
/* Function to call to decide whether or not a word break character is
quoted. If a character is quoted, it does not break words for the
completer. */
extern rl_linebuf_func_t *rl_char_is_quoted_p;
/* Non-zero means to suppress normal filename completion after the
user-specified completion function has been called. */
extern int rl_attempted_completion_over;
/* Set to a character describing the type of completion being attempted by
rl_complete_internal; available for use by application completion
functions. */
extern int rl_completion_type;
/* Set to the last key used to invoke one of the completion functions */
extern int rl_completion_invoking_key;
/* Up to this many items will be displayed in response to a
possible-completions call. After that, we ask the user if she
is sure she wants to see them all. The default value is 100. */
extern int rl_completion_query_items;
/* Character appended to completed words when at the end of the line. The
default is a space. Nothing is added if this is '\0'. */
extern int rl_completion_append_character;
/* If set to non-zero by an application completion function,
rl_completion_append_character will not be appended. */
extern int rl_completion_suppress_append;
/* Set to any quote character readline thinks it finds before any application
completion function is called. */
extern int rl_completion_quote_character;
/* Set to a non-zero value if readline found quoting anywhere in the word to
be completed; set before any application completion function is called. */
extern int rl_completion_found_quote;
/* If non-zero, the completion functions don't append any closing quote.
This is set to 0 by rl_complete_internal and may be changed by an
application-specific completion function. */
extern int rl_completion_suppress_quote;
/* If non-zero, readline will sort the completion matches. On by default. */
extern int rl_sort_completion_matches;
/* If non-zero, a slash will be appended to completed filenames that are
symbolic links to directory names, subject to the value of the
mark-directories variable (which is user-settable). This exists so
that application completion functions can override the user's preference
(set via the mark-symlinked-directories variable) if appropriate.
It's set to the value of _rl_complete_mark_symlink_dirs in
rl_complete_internal before any application-specific completion
function is called, so without that function doing anything, the user's
preferences are honored. */
extern int rl_completion_mark_symlink_dirs;
/* If non-zero, then disallow duplicates in the matches. */
extern int rl_ignore_completion_duplicates;
/* If this is non-zero, completion is (temporarily) inhibited, and the
completion character will be inserted as any other. */
extern int rl_inhibit_completion;
/* Input error; can be returned by (*rl_getc_function) if readline is reading
a top-level command (RL_ISSTATE (RL_STATE_READCMD)). */
#define READERR (-2)
/* Definitions available for use by readline clients. */
#define RL_PROMPT_START_IGNORE '\001'
#define RL_PROMPT_END_IGNORE '\002'
/* Possible values for do_replace argument to rl_filename_quoting_function,
called by rl_complete_internal. */
#define NO_MATCH 0
#define SINGLE_MATCH 1
#define MULT_MATCH 2
/* Possible state values for rl_readline_state */
#define RL_STATE_NONE 0x000000 /* no state; before first call */
#define RL_STATE_INITIALIZING 0x0000001 /* initializing */
#define RL_STATE_INITIALIZED 0x0000002 /* initialization done */
#define RL_STATE_TERMPREPPED 0x0000004 /* terminal is prepped */
#define RL_STATE_READCMD 0x0000008 /* reading a command key */
#define RL_STATE_METANEXT 0x0000010 /* reading input after ESC */
#define RL_STATE_DISPATCHING 0x0000020 /* dispatching to a command */
#define RL_STATE_MOREINPUT 0x0000040 /* reading more input in a command function */
#define RL_STATE_ISEARCH 0x0000080 /* doing incremental search */
#define RL_STATE_NSEARCH 0x0000100 /* doing non-inc search */
#define RL_STATE_SEARCH 0x0000200 /* doing a history search */
#define RL_STATE_NUMERICARG 0x0000400 /* reading numeric argument */
#define RL_STATE_MACROINPUT 0x0000800 /* getting input from a macro */
#define RL_STATE_MACRODEF 0x0001000 /* defining keyboard macro */
#define RL_STATE_OVERWRITE 0x0002000 /* overwrite mode */
#define RL_STATE_COMPLETING 0x0004000 /* doing completion */
#define RL_STATE_SIGHANDLER 0x0008000 /* in readline sighandler */
#define RL_STATE_UNDOING 0x0010000 /* doing an undo */
#define RL_STATE_INPUTPENDING 0x0020000 /* rl_execute_next called */
#define RL_STATE_TTYCSAVED 0x0040000 /* tty special chars saved */
#define RL_STATE_CALLBACK 0x0080000 /* using the callback interface */
#define RL_STATE_VIMOTION 0x0100000 /* reading vi motion arg */
#define RL_STATE_MULTIKEY 0x0200000 /* reading multiple-key command */
#define RL_STATE_VICMDONCE 0x0400000 /* entered vi command mode at least once */
#define RL_STATE_REDISPLAYING 0x0800000 /* updating terminal display */
#define RL_STATE_DONE 0x1000000 /* done; accepted line */
#define RL_SETSTATE(x) (rl_readline_state |= (x))
#define RL_UNSETSTATE(x) (rl_readline_state &= ~(x))
#define RL_ISSTATE(x) (rl_readline_state & (x))
struct readline_state {
/* line state */
int point;
int end;
int mark;
char *buffer;
int buflen;
UNDO_LIST *ul;
char *prompt;
/* global state */
int rlstate;
int done;
Keymap kmap;
/* input state */
rl_command_func_t *lastfunc;
int insmode;
int edmode;
int kseqlen;
FILE *inf;
FILE *outf;
int pendingin;
char *macro;
/* signal state */
int catchsigs;
int catchsigwinch;
/* search state */
/* completion state */
/* options state */
/* reserved for future expansion, so the struct size doesn't change */
char reserved[64];
};
extern int rl_save_state PARAMS((struct readline_state *));
extern int rl_restore_state PARAMS((struct readline_state *));
#ifdef __cplusplus
}
#endif
#endif /* _READLINE_H_ */
+71 -12
View File
@@ -43,6 +43,7 @@
#include "readline.h"
#include "history.h"
#include "histlib.h"
#include "rlprivate.h"
#include "xmalloc.h"
@@ -66,6 +67,8 @@ static char *prev_line_found = (char *) NULL;
static int rl_history_search_len;
static int rl_history_search_pos;
static int rl_history_search_flags;
static char *history_search_string;
static int history_string_size;
@@ -74,7 +77,7 @@ static int noninc_search_from_pos PARAMS((char *, int, int));
static int noninc_dosearch PARAMS((char *, int));
static int noninc_search PARAMS((int, int));
static int rl_history_search_internal PARAMS((int, int));
static void rl_history_search_reinit PARAMS((void));
static void rl_history_search_reinit PARAMS((int));
static _rl_search_cxt *_rl_nsearch_init PARAMS((int, int));
static int _rl_nsearch_cleanup PARAMS((_rl_search_cxt *, int));
@@ -453,13 +456,16 @@ rl_history_search_internal (count, dir)
{
HIST_ENTRY *temp;
int ret, oldpos;
char *t;
rl_maybe_save_line ();
temp = (HIST_ENTRY *)NULL;
/* Search COUNT times through the history for a line whose prefix
matches history_search_string. When this loop finishes, TEMP,
if non-null, is the history line to copy into the line buffer. */
/* Search COUNT times through the history for a line matching
history_search_string. If history_search_string[0] == '^', the
line must match from the start; otherwise any substring can match.
When this loop finishes, TEMP, if non-null, is the history line to
copy into the line buffer. */
while (count)
{
ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
@@ -505,35 +511,49 @@ rl_history_search_internal (count, dir)
/* Copy the line we found into the current line buffer. */
make_history_line_current (temp);
rl_point = rl_history_search_len;
if (rl_history_search_flags & ANCHORED_SEARCH)
rl_point = rl_history_search_len; /* easy case */
else
{
t = strstr (rl_line_buffer, history_search_string);
rl_point = t ? (int)(t - rl_line_buffer) + rl_history_search_len : rl_end;
}
rl_mark = rl_end;
return 0;
}
static void
rl_history_search_reinit ()
rl_history_search_reinit (flags)
int flags;
{
int sind;
rl_history_search_pos = where_history ();
rl_history_search_len = rl_point;
rl_history_search_flags = flags;
prev_line_found = (char *)NULL;
if (rl_point)
{
/* Allocate enough space for anchored and non-anchored searches */
if (rl_history_search_len >= history_string_size - 2)
{
history_string_size = rl_history_search_len + 2;
history_search_string = (char *)xrealloc (history_search_string, history_string_size);
}
history_search_string[0] = '^';
strncpy (history_search_string + 1, rl_line_buffer, rl_point);
history_search_string[rl_point + 1] = '\0';
sind = 0;
if (flags & ANCHORED_SEARCH)
history_search_string[sind++] = '^';
strncpy (history_search_string + sind, rl_line_buffer, rl_point);
history_search_string[rl_point + sind] = '\0';
}
_rl_free_saved_history_line ();
}
/* Search forward in the history for the string of characters
from the start of the line to rl_point. This is a non-incremental
search. */
search. The search is anchored to the beginning of the history line. */
int
rl_history_search_forward (count, ignore)
int count, ignore;
@@ -543,7 +563,7 @@ rl_history_search_forward (count, ignore)
if (rl_last_func != rl_history_search_forward &&
rl_last_func != rl_history_search_backward)
rl_history_search_reinit ();
rl_history_search_reinit (ANCHORED_SEARCH);
if (rl_history_search_len == 0)
return (rl_get_next_history (count, ignore));
@@ -562,7 +582,46 @@ rl_history_search_backward (count, ignore)
if (rl_last_func != rl_history_search_forward &&
rl_last_func != rl_history_search_backward)
rl_history_search_reinit ();
rl_history_search_reinit (ANCHORED_SEARCH);
if (rl_history_search_len == 0)
return (rl_get_previous_history (count, ignore));
return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
}
/* Search forward in the history for the string of characters
from the start of the line to rl_point. This is a non-incremental
search. The search succeeds if the search string is present anywhere
in the history line. */
int
rl_history_substr_search_forward (count, ignore)
int count, ignore;
{
if (count == 0)
return (0);
if (rl_last_func != rl_history_substr_search_forward &&
rl_last_func != rl_history_substr_search_backward)
rl_history_search_reinit (NON_ANCHORED_SEARCH);
if (rl_history_search_len == 0)
return (rl_get_next_history (count, ignore));
return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
}
/* Search backward through the history for the string of characters
from the start of the line to rl_point. This is a non-incremental
search. */
int
rl_history_substr_search_backward (count, ignore)
int count, ignore;
{
if (count == 0)
return (0);
if (rl_last_func != rl_history_substr_search_forward &&
rl_last_func != rl_history_substr_search_backward)
rl_history_search_reinit (NON_ANCHORED_SEARCH);
if (rl_history_search_len == 0)
return (rl_get_previous_history (count, ignore));
+590
View File
@@ -0,0 +1,590 @@
/* search.c - code for non-incremental searching in emacs and vi modes. */
/* Copyright (C) 1992-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 <sys/types.h>
#include <stdio.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if defined (HAVE_STDLIB_H)
# include <stdlib.h>
#else
# include "ansi_stdlib.h"
#endif
#include "rldefs.h"
#include "rlmbutil.h"
#include "readline.h"
#include "history.h"
#include "histlib.h"
#include "rlprivate.h"
#include "xmalloc.h"
#ifdef abs
# undef abs
#endif
#define abs(x) (((x) >= 0) ? (x) : -(x))
_rl_search_cxt *_rl_nscxt = 0;
extern HIST_ENTRY *_rl_saved_line_for_history;
/* Functions imported from the rest of the library. */
extern int _rl_free_history_entry PARAMS((HIST_ENTRY *));
static char *noninc_search_string = (char *) NULL;
static int noninc_history_pos;
static char *prev_line_found = (char *) NULL;
static int rl_history_search_len;
static int rl_history_search_pos;
static int rl_history_search_flags;
static char *history_search_string;
static int history_string_size;
static void make_history_line_current PARAMS((HIST_ENTRY *));
static int noninc_search_from_pos PARAMS((char *, int, int));
static int noninc_dosearch PARAMS((char *, int));
static int noninc_search PARAMS((int, int));
static int rl_history_search_internal PARAMS((int, int));
static void rl_history_search_reinit PARAMS((int));
static _rl_search_cxt *_rl_nsearch_init PARAMS((int, int));
static int _rl_nsearch_cleanup PARAMS((_rl_search_cxt *, int));
static void _rl_nsearch_abort PARAMS((_rl_search_cxt *));
static int _rl_nsearch_dispatch PARAMS((_rl_search_cxt *, int));
/* Make the data from the history entry ENTRY be the contents of the
current line. This doesn't do anything with rl_point; the caller
must set it. */
static void
make_history_line_current (entry)
HIST_ENTRY *entry;
{
_rl_replace_text (entry->line, 0, rl_end);
_rl_fix_point (1);
#if defined (VI_MODE)
if (rl_editing_mode == vi_mode)
/* POSIX.2 says that the `U' command doesn't affect the copy of any
command lines to the edit line. We're going to implement that by
making the undo list start after the matching line is copied to the
current editing buffer. */
rl_free_undo_list ();
#endif
if (_rl_saved_line_for_history)
_rl_free_history_entry (_rl_saved_line_for_history);
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
}
/* Search the history list for STRING starting at absolute history position
POS. If STRING begins with `^', the search must match STRING at the
beginning of a history line, otherwise a full substring match is performed
for STRING. DIR < 0 means to search backwards through the history list,
DIR >= 0 means to search forward. */
static int
noninc_search_from_pos (string, pos, dir)
char *string;
int pos, dir;
{
int ret, old;
if (pos < 0)
return -1;
old = where_history ();
if (history_set_pos (pos) == 0)
return -1;
RL_SETSTATE(RL_STATE_SEARCH);
if (*string == '^')
ret = history_search_prefix (string + 1, dir);
else
ret = history_search (string, dir);
RL_UNSETSTATE(RL_STATE_SEARCH);
if (ret != -1)
ret = where_history ();
history_set_pos (old);
return (ret);
}
/* Search for a line in the history containing STRING. If DIR is < 0, the
search is backwards through previous entries, else through subsequent
entries. Returns 1 if the search was successful, 0 otherwise. */
static int
noninc_dosearch (string, dir)
char *string;
int dir;
{
int oldpos, pos;
HIST_ENTRY *entry;
if (string == 0 || *string == '\0' || noninc_history_pos < 0)
{
rl_ding ();
return 0;
}
pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
if (pos == -1)
{
/* Search failed, current history position unchanged. */
rl_maybe_unsave_line ();
rl_clear_message ();
rl_point = 0;
rl_ding ();
return 0;
}
noninc_history_pos = pos;
oldpos = where_history ();
history_set_pos (noninc_history_pos);
entry = current_history ();
#if defined (VI_MODE)
if (rl_editing_mode != vi_mode)
#endif
history_set_pos (oldpos);
make_history_line_current (entry);
rl_point = 0;
rl_mark = rl_end;
rl_clear_message ();
return 1;
}
static _rl_search_cxt *
_rl_nsearch_init (dir, pchar)
int dir, pchar;
{
_rl_search_cxt *cxt;
char *p;
cxt = _rl_scxt_alloc (RL_SEARCH_NSEARCH, 0);
if (dir < 0)
cxt->sflags |= SF_REVERSE; /* not strictly needed */
cxt->direction = dir;
cxt->history_pos = cxt->save_line;
rl_maybe_save_line ();
/* Clear the undo list, since reading the search string should create its
own undo list, and the whole list will end up being freed when we
finish reading the search string. */
rl_undo_list = 0;
/* Use the line buffer to read the search string. */
rl_line_buffer[0] = 0;
rl_end = rl_point = 0;
p = _rl_make_prompt_for_search (pchar ? pchar : ':');
rl_message ("%s", p, 0);
xfree (p);
RL_SETSTATE(RL_STATE_NSEARCH);
_rl_nscxt = cxt;
return cxt;
}
static int
_rl_nsearch_cleanup (cxt, r)
_rl_search_cxt *cxt;
int r;
{
_rl_scxt_dispose (cxt, 0);
_rl_nscxt = 0;
RL_UNSETSTATE(RL_STATE_NSEARCH);
return (r != 1);
}
static void
_rl_nsearch_abort (cxt)
_rl_search_cxt *cxt;
{
rl_maybe_unsave_line ();
rl_clear_message ();
rl_point = cxt->save_point;
rl_mark = cxt->save_mark;
rl_restore_prompt ();
RL_UNSETSTATE (RL_STATE_NSEARCH);
}
/* Process just-read character C according to search context CXT. Return -1
if the caller should abort the search, 0 if we should break out of the
loop, and 1 if we should continue to read characters. */
static int
_rl_nsearch_dispatch (cxt, c)
_rl_search_cxt *cxt;
int c;
{
switch (c)
{
case CTRL('W'):
rl_unix_word_rubout (1, c);
break;
case CTRL('U'):
rl_unix_line_discard (1, c);
break;
case RETURN:
case NEWLINE:
return 0;
case CTRL('H'):
case RUBOUT:
if (rl_point == 0)
{
_rl_nsearch_abort (cxt);
return -1;
}
_rl_rubout_char (1, c);
break;
case CTRL('C'):
case CTRL('G'):
rl_ding ();
_rl_nsearch_abort (cxt);
return -1;
default:
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
rl_insert_text (cxt->mb);
else
#endif
_rl_insert_char (1, c);
break;
}
(*rl_redisplay_function) ();
return 1;
}
/* Perform one search according to CXT, using NONINC_SEARCH_STRING. Return
-1 if the search should be aborted, any other value means to clean up
using _rl_nsearch_cleanup (). Returns 1 if the search was successful,
0 otherwise. */
static int
_rl_nsearch_dosearch (cxt)
_rl_search_cxt *cxt;
{
rl_mark = cxt->save_mark;
/* If rl_point == 0, we want to re-use the previous search string and
start from the saved history position. If there's no previous search
string, punt. */
if (rl_point == 0)
{
if (noninc_search_string == 0)
{
rl_ding ();
rl_restore_prompt ();
RL_UNSETSTATE (RL_STATE_NSEARCH);
return -1;
}
}
else
{
/* We want to start the search from the current history position. */
noninc_history_pos = cxt->save_line;
FREE (noninc_search_string);
noninc_search_string = savestring (rl_line_buffer);
/* If we don't want the subsequent undo list generated by the search
matching a history line to include the contents of the search string,
we need to clear rl_line_buffer here. For now, we just clear the
undo list generated by reading the search string. (If the search
fails, the old undo list will be restored by rl_maybe_unsave_line.) */
rl_free_undo_list ();
}
rl_restore_prompt ();
return (noninc_dosearch (noninc_search_string, cxt->direction));
}
/* Search non-interactively through the history list. DIR < 0 means to
search backwards through the history of previous commands; otherwise
the search is for commands subsequent to the current position in the
history list. PCHAR is the character to use for prompting when reading
the search string; if not specified (0), it defaults to `:'. */
static int
noninc_search (dir, pchar)
int dir;
int pchar;
{
_rl_search_cxt *cxt;
int c, r;
cxt = _rl_nsearch_init (dir, pchar);
if (RL_ISSTATE (RL_STATE_CALLBACK))
return (0);
/* Read the search string. */
r = 0;
while (1)
{
c = _rl_search_getchar (cxt);
if (c == 0)
break;
r = _rl_nsearch_dispatch (cxt, c);
if (r < 0)
return 1;
else if (r == 0)
break;
}
r = _rl_nsearch_dosearch (cxt);
return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
}
/* Search forward through the history list for a string. If the vi-mode
code calls this, KEY will be `?'. */
int
rl_noninc_forward_search (count, key)
int count, key;
{
return noninc_search (1, (key == '?') ? '?' : 0);
}
/* Reverse search the history list for a string. If the vi-mode code
calls this, KEY will be `/'. */
int
rl_noninc_reverse_search (count, key)
int count, key;
{
return noninc_search (-1, (key == '/') ? '/' : 0);
}
/* Search forward through the history list for the last string searched
for. If there is no saved search string, abort. */
int
rl_noninc_forward_search_again (count, key)
int count, key;
{
int r;
if (!noninc_search_string)
{
rl_ding ();
return (-1);
}
r = noninc_dosearch (noninc_search_string, 1);
return (r != 1);
}
/* Reverse search in the history list for the last string searched
for. If there is no saved search string, abort. */
int
rl_noninc_reverse_search_again (count, key)
int count, key;
{
int r;
if (!noninc_search_string)
{
rl_ding ();
return (-1);
}
r = noninc_dosearch (noninc_search_string, -1);
return (r != 1);
}
#if defined (READLINE_CALLBACKS)
int
_rl_nsearch_callback (cxt)
_rl_search_cxt *cxt;
{
int c, r;
c = _rl_search_getchar (cxt);
r = _rl_nsearch_dispatch (cxt, c);
if (r != 0)
return 1;
r = _rl_nsearch_dosearch (cxt);
return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
}
#endif
static int
rl_history_search_internal (count, dir)
int count, dir;
{
HIST_ENTRY *temp;
int ret, oldpos;
char *t;
rl_maybe_save_line ();
temp = (HIST_ENTRY *)NULL;
/* Search COUNT times through the history for a line matching
history_search_string. If history_search_string[0] == '^', the
line must match from the start; otherwise any substring can match.
When this loop finishes, TEMP, if non-null, is the history line to
copy into the line buffer. */
while (count)
{
ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
if (ret == -1)
break;
/* Get the history entry we found. */
rl_history_search_pos = ret;
oldpos = where_history ();
history_set_pos (rl_history_search_pos);
temp = current_history ();
history_set_pos (oldpos);
/* Don't find multiple instances of the same line. */
if (prev_line_found && STREQ (prev_line_found, temp->line))
continue;
prev_line_found = temp->line;
count--;
}
/* If we didn't find anything at all, return. */
if (temp == 0)
{
rl_maybe_unsave_line ();
rl_ding ();
/* If you don't want the saved history line (last match) to show up
in the line buffer after the search fails, change the #if 0 to
#if 1 */
#if 0
if (rl_point > rl_history_search_len)
{
rl_point = rl_end = rl_history_search_len;
rl_line_buffer[rl_end] = '\0';
rl_mark = 0;
}
#else
rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */
rl_mark = rl_end;
#endif
return 1;
}
/* Copy the line we found into the current line buffer. */
make_history_line_current (temp);
if (rl_history_search_flags & ANCHORED_SEARCH)
rl_point = rl_history_search_len; /* easy case */
else
{
t = strstr (rl_line_buffer, history_search_string);
rl_point = t ? (int)(t - rl_line_buffer) + rl_history_search_len : rl_end;
}
rl_mark = rl_end;
return 0;
}
static void
rl_history_search_reinit (flags)
int flags;
{
int sind;
rl_history_search_pos = where_history ();
rl_history_search_len = rl_point;
rl_history_search_flags = flags;
prev_line_found = (char *)NULL;
if (rl_point)
{
/* Allocate enough space for anchored and non-anchored searches */
if (rl_history_search_len >= history_string_size - 2)
{
history_string_size = rl_history_search_len + 2;
history_search_string = (char *)xrealloc (history_search_string, history_string_size);
}
sind = 0;
if (flags & ANCHORED_SEARCH)
history_search_string[sind++] = '^';
strncpy (history_search_string + sind, rl_line_buffer, rl_point);
history_search_string[rl_point + sind] = '\0';
}
_rl_free_saved_history_line ();
}
/* Search forward in the history for the string of characters
from the start of the line to rl_point. This is a non-incremental
search. */
int
rl_history_search_forward (count, ignore)
int count, ignore;
{
if (count == 0)
return (0);
if (rl_last_func != rl_history_search_forward &&
rl_last_func != rl_history_search_backward)
rl_history_search_reinit (ANCHORED_SEARCH);
if (rl_history_search_len == 0)
return (rl_get_next_history (count, ignore));
return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
}
/* Search backward through the history for the string of characters
from the start of the line to rl_point. This is a non-incremental
search. */
int
rl_history_search_backward (count, ignore)
int count, ignore;
{
if (count == 0)
return (0);
if (rl_last_func != rl_history_search_forward &&
rl_last_func != rl_history_search_backward)
rl_history_search_reinit (ANCHORED_SEARCH);
if (rl_history_search_len == 0)
return (rl_get_previous_history (count, ignore));
return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
}
+10 -6
View File
@@ -801,13 +801,17 @@ wait_for (pid)
return_val = process_exit_status (status);
last_command_exit_signal = get_termsig (status);
#if !defined (DONT_REPORT_SIGPIPE)
if ((WIFSTOPPED (status) == 0) && WIFSIGNALED (status) &&
(WTERMSIG (status) != SIGINT))
#if defined (DONT_REPORT_SIGPIPE) && defined (DONT_REPORT_SIGTERM)
# define REPORTSIG(x) ((x) != SIGINT && (x) != SIGPIPE && (x) != SIGTERM)
#elif !defined (DONT_REPORT_SIGPIPE) && !defined (DONT_REPORT_SIGTERM)
# define REPORTSIG(x) ((x) != SIGINT)
#elif defined (DONT_REPORT_SIGPIPE)
# define REPORTSIG(x) ((x) != SIGINT && (x) != SIGPIPE)
#else
if ((WIFSTOPPED (status) == 0) && WIFSIGNALED (status) &&
(WTERMSIG (status) != SIGINT) && (WTERMSIG (status) != SIGPIPE))
#endif
# define REPORTSIG(x) ((x) != SIGINT && (x) != SIGTERM)
#endiof
if ((WIFSTOPPED (status) == 0) && WIFSIGNALED (status) && REPORTSIG(WTERMSIG (status)))
{
fprintf (stderr, "%s", j_strsignal (WTERMSIG (status)));
if (WIFCORED (status))
+943
View File
@@ -0,0 +1,943 @@
/* nojobs.c - functions that make children, remember them, and handle their termination. */
/* This file works under BSD, System V, minix, and Posix systems. It does
not implement job control. */
/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "bashtypes.h"
#include "filecntl.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#if defined (BUFFERED_INPUT)
# include "input.h"
#endif
/* Need to include this up here for *_TTY_DRIVER definitions. */
#include "shtty.h"
#include "bashintl.h"
#include "shell.h"
#include "jobs.h"
#include "execute_cmd.h"
#include "builtins/builtext.h" /* for wait_builtin */
#define DEFAULT_CHILD_MAX 32
#if defined (_POSIX_VERSION) || !defined (HAVE_KILLPG)
# define killpg(pg, sig) kill(-(pg),(sig))
#endif /* USG || _POSIX_VERSION */
#if !defined (HAVE_SIGINTERRUPT) && !defined (HAVE_POSIX_SIGNALS)
# define siginterrupt(sig, code)
#endif /* !HAVE_SIGINTERRUPT && !HAVE_POSIX_SIGNALS */
#if defined (HAVE_WAITPID)
# define WAITPID(pid, statusp, options) waitpid (pid, statusp, options)
#else
# define WAITPID(pid, statusp, options) wait (statusp)
#endif /* !HAVE_WAITPID */
/* Return the fd from which we are actually getting input. */
#define input_tty() (shell_tty != -1) ? shell_tty : fileno (stderr)
#if !defined (errno)
extern int errno;
#endif /* !errno */
extern int interactive, interactive_shell, login_shell;
extern int subshell_environment;
extern int last_command_exit_value, last_command_exit_signal;
extern int interrupt_immediately;
extern sh_builtin_func_t *this_shell_builtin;
#if defined (HAVE_POSIX_SIGNALS)
extern sigset_t top_level_mask;
#endif
extern procenv_t wait_intr_buf;
extern int wait_signal_received;
pid_t last_made_pid = NO_PID;
pid_t last_asynchronous_pid = NO_PID;
/* Call this when you start making children. */
int already_making_children = 0;
/* The controlling tty for this shell. */
int shell_tty = -1;
/* If this is non-zero, $LINES and $COLUMNS are reset after every process
exits from get_tty_state(). */
int check_window_size;
/* STATUS and FLAGS are only valid if pid != NO_PID
STATUS is only valid if (flags & PROC_RUNNING) == 0 */
struct proc_status {
pid_t pid;
int status; /* Exit status of PID or 128 + fatal signal number */
int flags;
};
/* Values for proc_status.flags */
#define PROC_RUNNING 0x01
#define PROC_NOTIFIED 0x02
#define PROC_ASYNC 0x04
#define PROC_SIGNALED 0x10
/* Return values from find_status_by_pid */
#define PROC_BAD -1
#define PROC_STILL_ALIVE -2
static struct proc_status *pid_list = (struct proc_status *)NULL;
static int pid_list_size;
static int wait_sigint_received;
static long child_max = -1L;
static void alloc_pid_list __P((void));
static int find_proc_slot __P((void));
static int find_index_by_pid __P((pid_t));
static int find_status_by_pid __P((pid_t));
static int process_exit_status __P((WAIT));
static int find_termsig_by_pid __P((pid_t));
static int get_termsig __P((WAIT));
static void set_pid_status __P((pid_t, WAIT));
static void set_pid_flags __P((pid_t, int));
static void unset_pid_flags __P((pid_t, int));
static int get_pid_flags __P((pid_t));
static void add_pid __P((pid_t, int));
static void mark_dead_jobs_as_notified __P((int));
static sighandler wait_sigint_handler __P((int));
static char *j_strsignal __P((int));
#if defined (HAVE_WAITPID)
static void reap_zombie_children __P((void));
#endif
#if !defined (HAVE_SIGINTERRUPT) && defined (HAVE_POSIX_SIGNALS)
static int siginterrupt __P((int, int));
#endif
static void restore_sigint_handler __P((void));
/* Allocate new, or grow existing PID_LIST. */
static void
alloc_pid_list ()
{
register int i;
int old = pid_list_size;
pid_list_size += 10;
pid_list = (struct proc_status *)xrealloc (pid_list, pid_list_size * sizeof (struct proc_status));
/* None of the newly allocated slots have process id's yet. */
for (i = old; i < pid_list_size; i++)
pid_list[i].pid = NO_PID;
}
/* Return the offset within the PID_LIST array of an empty slot. This can
create new slots if all of the existing slots are taken. */
static int
find_proc_slot ()
{
register int i;
for (i = 0; i < pid_list_size; i++)
if (pid_list[i].pid == NO_PID)
return (i);
if (i == pid_list_size)
alloc_pid_list ();
return (i);
}
/* Return the offset within the PID_LIST array of a slot containing PID,
or the value NO_PID if the pid wasn't found. */
static int
find_index_by_pid (pid)
pid_t pid;
{
register int i;
for (i = 0; i < pid_list_size; i++)
if (pid_list[i].pid == pid)
return (i);
return (NO_PID);
}
/* Return the status of PID as looked up in the PID_LIST array. A
return value of PROC_BAD indicates that PID wasn't found. */
static int
find_status_by_pid (pid)
pid_t pid;
{
int i;
i = find_index_by_pid (pid);
if (i == NO_PID)
return (PROC_BAD);
if (pid_list[i].flags & PROC_RUNNING)
return (PROC_STILL_ALIVE);
return (pid_list[i].status);
}
static int
process_exit_status (status)
WAIT status;
{
if (WIFSIGNALED (status))
return (128 + WTERMSIG (status));
else
return (WEXITSTATUS (status));
}
/* Return the status of PID as looked up in the PID_LIST array. A
return value of PROC_BAD indicates that PID wasn't found. */
static int
find_termsig_by_pid (pid)
pid_t pid;
{
int i;
i = find_index_by_pid (pid);
if (i == NO_PID)
return (0);
if (pid_list[i].flags & PROC_RUNNING)
return (0);
return (get_termsig ((WAIT)pid_list[i].status));
}
/* Set LAST_COMMAND_EXIT_SIGNAL depending on STATUS. If STATUS is -1, look
up PID in the pid array and set LAST_COMMAND_EXIT_SIGNAL appropriately
depending on its flags and exit status. */
static int
get_termsig (status)
WAIT status;
{
if (WIFSTOPPED (status) == 0 && WIFSIGNALED (status))
return (WTERMSIG (status));
else
return (0);
}
/* Give PID the status value STATUS in the PID_LIST array. */
static void
set_pid_status (pid, status)
pid_t pid;
WAIT status;
{
int slot;
#if defined (COPROCESS_SUPPORT)
coproc_pidchk (pid, status);
#endif
slot = find_index_by_pid (pid);
if (slot == NO_PID)
return;
pid_list[slot].status = process_exit_status (status);
pid_list[slot].flags &= ~PROC_RUNNING;
if (WIFSIGNALED (status))
pid_list[slot].flags |= PROC_SIGNALED;
/* If it's not a background process, mark it as notified so it gets
cleaned up. */
if ((pid_list[slot].flags & PROC_ASYNC) == 0)
pid_list[slot].flags |= PROC_NOTIFIED;
}
/* Give PID the flags FLAGS in the PID_LIST array. */
static void
set_pid_flags (pid, flags)
pid_t pid;
int flags;
{
int slot;
slot = find_index_by_pid (pid);
if (slot == NO_PID)
return;
pid_list[slot].flags |= flags;
}
/* Unset FLAGS for PID in the pid list */
static void
unset_pid_flags (pid, flags)
pid_t pid;
int flags;
{
int slot;
slot = find_index_by_pid (pid);
if (slot == NO_PID)
return;
pid_list[slot].flags &= ~flags;
}
/* Return the flags corresponding to PID in the PID_LIST array. */
static int
get_pid_flags (pid)
pid_t pid;
{
int slot;
slot = find_index_by_pid (pid);
if (slot == NO_PID)
return 0;
return (pid_list[slot].flags);
}
static void
add_pid (pid, async)
pid_t pid;
int async;
{
int slot;
slot = find_proc_slot ();
pid_list[slot].pid = pid;
pid_list[slot].status = -1;
pid_list[slot].flags = PROC_RUNNING;
if (async)
pid_list[slot].flags |= PROC_ASYNC;
}
static void
mark_dead_jobs_as_notified (force)
int force;
{
register int i, ndead;
/* first, count the number of non-running async jobs if FORCE == 0 */
for (i = ndead = 0; force == 0 && i < pid_list_size; i++)
{
if (pid_list[i].pid == NO_PID)
continue;
if (((pid_list[i].flags & PROC_RUNNING) == 0) &&
(pid_list[i].flags & PROC_ASYNC))
ndead++;
}
if (child_max < 0)
child_max = getmaxchild ();
if (child_max < 0)
child_max = DEFAULT_CHILD_MAX;
if (force == 0 && ndead <= child_max)
return;
/* If FORCE == 0, we just mark as many non-running async jobs as notified
to bring us under the CHILD_MAX limit. */
for (i = 0; i < pid_list_size; i++)
{
if (pid_list[i].pid == NO_PID)
continue;
if (((pid_list[i].flags & PROC_RUNNING) == 0) &&
pid_list[i].pid != last_asynchronous_pid)
{
pid_list[i].flags |= PROC_NOTIFIED;
if (force == 0 && (pid_list[i].flags & PROC_ASYNC) && --ndead <= child_max)
break;
}
}
}
/* Remove all dead, notified jobs from the pid_list. */
int
cleanup_dead_jobs ()
{
register int i;
#if defined (HAVE_WAITPID)
reap_zombie_children ();
#endif
for (i = 0; i < pid_list_size; i++)
{
if ((pid_list[i].flags & PROC_RUNNING) == 0 &&
(pid_list[i].flags & PROC_NOTIFIED))
pid_list[i].pid = NO_PID;
}
#if defined (COPROCESS_SUPPORT)
coproc_reap ();
#endif
return 0;
}
void
reap_dead_jobs ()
{
mark_dead_jobs_as_notified (0);
cleanup_dead_jobs ();
}
/* Initialize the job control mechanism, and set up the tty stuff. */
initialize_job_control (force)
int force;
{
shell_tty = fileno (stderr);
if (interactive)
get_tty_state ();
}
/* Setup this shell to handle C-C, etc. */
void
initialize_job_signals ()
{
set_signal_handler (SIGINT, sigint_sighandler);
/* If this is a login shell we don't wish to be disturbed by
stop signals. */
if (login_shell)
ignore_tty_job_signals ();
}
#if defined (HAVE_WAITPID)
/* Collect the status of all zombie children so that their system
resources can be deallocated. */
static void
reap_zombie_children ()
{
# if defined (WNOHANG)
pid_t pid;
WAIT status;
CHECK_TERMSIG;
while ((pid = waitpid (-1, (int *)&status, WNOHANG)) > 0)
set_pid_status (pid, status);
# endif /* WNOHANG */
CHECK_TERMSIG;
}
#endif /* WAITPID */
#if !defined (HAVE_SIGINTERRUPT) && defined (HAVE_POSIX_SIGNALS)
static int
siginterrupt (sig, flag)
int sig, flag;
{
struct sigaction act;
sigaction (sig, (struct sigaction *)NULL, &act);
if (flag)
act.sa_flags &= ~SA_RESTART;
else
act.sa_flags |= SA_RESTART;
return (sigaction (sig, &act, (struct sigaction *)NULL));
}
#endif /* !HAVE_SIGINTERRUPT && HAVE_POSIX_SIGNALS */
/* Fork, handling errors. Returns the pid of the newly made child, or 0.
COMMAND is just for remembering the name of the command; we don't do
anything else with it. ASYNC_P says what to do with the tty. If
non-zero, then don't give it away. */
pid_t
make_child (command, async_p)
char *command;
int async_p;
{
pid_t pid;
int forksleep;
/* Discard saved memory. */
if (command)
free (command);
start_pipeline ();
#if defined (BUFFERED_INPUT)
/* If default_buffered_input is active, we are reading a script. If
the command is asynchronous, we have already duplicated /dev/null
as fd 0, but have not changed the buffered stream corresponding to
the old fd 0. We don't want to sync the stream in this case. */
if (default_buffered_input != -1 && (!async_p || default_buffered_input > 0))
sync_buffered_stream (default_buffered_input);
#endif /* BUFFERED_INPUT */
/* Create the child, handle severe errors. Retry on EAGAIN. */
forksleep = 1;
while ((pid = fork ()) < 0 && errno == EAGAIN && forksleep < FORKSLEEP_MAX)
{
sys_error ("fork: retry");
#if defined (HAVE_WAITPID)
/* Posix systems with a non-blocking waitpid () system call available
get another chance after zombies are reaped. */
reap_zombie_children ();
if (forksleep > 1 && sleep (forksleep) != 0)
break;
#else
if (sleep (forksleep) != 0)
break;
#endif /* HAVE_WAITPID */
forksleep <<= 1;
}
if (pid < 0)
{
sys_error ("fork");
throw_to_top_level ();
}
if (pid == 0)
{
#if defined (BUFFERED_INPUT)
unset_bash_input (0);
#endif /* BUFFERED_INPUT */
#if defined (HAVE_POSIX_SIGNALS)
/* Restore top-level signal mask. */
sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
#endif
#if 0
/* Ignore INT and QUIT in asynchronous children. */
if (async_p)
last_asynchronous_pid = getpid ();
#endif
default_tty_job_signals ();
}
else
{
/* In the parent. */
last_made_pid = pid;
if (async_p)
last_asynchronous_pid = pid;
add_pid (pid, async_p);
}
return (pid);
}
void
ignore_tty_job_signals ()
{
#if defined (SIGTSTP)
set_signal_handler (SIGTSTP, SIG_IGN);
set_signal_handler (SIGTTIN, SIG_IGN);
set_signal_handler (SIGTTOU, SIG_IGN);
#endif
}
void
default_tty_job_signals ()
{
#if defined (SIGTSTP)
set_signal_handler (SIGTSTP, SIG_DFL);
set_signal_handler (SIGTTIN, SIG_DFL);
set_signal_handler (SIGTTOU, SIG_DFL);
#endif
}
/* Wait for a single pid (PID) and return its exit status. Called by
the wait builtin. */
int
wait_for_single_pid (pid)
pid_t pid;
{
pid_t got_pid;
WAIT status;
int pstatus, flags;
pstatus = find_status_by_pid (pid);
if (pstatus == PROC_BAD)
{
internal_error (_("wait: pid %ld is not a child of this shell"), (long)pid);
return (127);
}
if (pstatus != PROC_STILL_ALIVE)
{
if (pstatus > 128)
last_command_exit_signal = find_termsig_by_pid (pid);
return (pstatus);
}
siginterrupt (SIGINT, 1);
while ((got_pid = WAITPID (pid, &status, 0)) != pid)
{
CHECK_TERMSIG;
if (got_pid < 0)
{
if (errno != EINTR && errno != ECHILD)
{
siginterrupt (SIGINT, 0);
sys_error ("wait");
}
break;
}
else if (got_pid > 0)
set_pid_status (got_pid, status);
}
if (got_pid > 0)
{
set_pid_status (got_pid, status);
set_pid_flags (got_pid, PROC_NOTIFIED);
}
siginterrupt (SIGINT, 0);
QUIT;
return (got_pid > 0 ? process_exit_status (status) : -1);
}
/* Wait for all of the shell's children to exit. Called by the `wait'
builtin. */
void
wait_for_background_pids ()
{
pid_t got_pid;
WAIT status;
/* If we aren't using job control, we let the kernel take care of the
bookkeeping for us. wait () will return -1 and set errno to ECHILD
when there are no more unwaited-for child processes on both
4.2 BSD-based and System V-based systems. */
siginterrupt (SIGINT, 1);
/* Wait for ECHILD */
while ((got_pid = WAITPID (-1, &status, 0)) != -1)
set_pid_status (got_pid, status);
if (errno != EINTR && errno != ECHILD)
{
siginterrupt (SIGINT, 0);
sys_error("wait");
}
siginterrupt (SIGINT, 0);
QUIT;
mark_dead_jobs_as_notified (1);
cleanup_dead_jobs ();
}
/* Make OLD_SIGINT_HANDLER the SIGINT signal handler. */
#define INVALID_SIGNAL_HANDLER (SigHandler *)wait_for_background_pids
static SigHandler *old_sigint_handler = INVALID_SIGNAL_HANDLER;
static void
restore_sigint_handler ()
{
if (old_sigint_handler != INVALID_SIGNAL_HANDLER)
{
set_signal_handler (SIGINT, old_sigint_handler);
old_sigint_handler = INVALID_SIGNAL_HANDLER;
}
}
/* Handle SIGINT while we are waiting for children in a script to exit.
All interrupts are effectively ignored by the shell, but allowed to
kill a running job. */
static sighandler
wait_sigint_handler (sig)
int sig;
{
SigHandler *sigint_handler;
/* If we got a SIGINT while in `wait', and SIGINT is trapped, do
what POSIX.2 says (see builtins/wait.def for more info). */
if (this_shell_builtin && this_shell_builtin == wait_builtin &&
signal_is_trapped (SIGINT) &&
((sigint_handler = trap_to_sighandler (SIGINT)) == trap_handler))
{
last_command_exit_value = EXECUTION_FAILURE;
restore_sigint_handler ();
interrupt_immediately = 0;
trap_handler (SIGINT); /* set pending_traps[SIGINT] */
wait_signal_received = SIGINT;
longjmp (wait_intr_buf, 1);
}
if (interrupt_immediately)
{
last_command_exit_value = EXECUTION_FAILURE;
restore_sigint_handler ();
ADDINTERRUPT;
QUIT;
}
wait_sigint_received = 1;
SIGRETURN (0);
}
static char *
j_strsignal (s)
int s;
{
static char retcode_name_buffer[64] = { '\0' };
char *x;
x = strsignal (s);
if (x == 0)
{
x = retcode_name_buffer;
sprintf (x, "Signal %d", s);
}
return x;
}
/* Wait for pid (one of our children) to terminate. This is called only
by the execution code in execute_cmd.c. */
int
wait_for (pid)
pid_t pid;
{
int return_val, pstatus;
pid_t got_pid;
WAIT status;
pstatus = find_status_by_pid (pid);
if (pstatus == PROC_BAD)
return (0);
if (pstatus != PROC_STILL_ALIVE)
{
if (pstatus > 128)
last_command_exit_signal = find_termsig_by_pid (pid);
return (pstatus);
}
/* If we are running a script, ignore SIGINT while we're waiting for
a child to exit. The loop below does some of this, but not all. */
wait_sigint_received = 0;
if (interactive_shell == 0)
old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler);
while ((got_pid = WAITPID (-1, &status, 0)) != pid) /* XXX was pid now -1 */
{
CHECK_TERMSIG;
if (got_pid < 0 && errno == ECHILD)
{
#if !defined (_POSIX_VERSION)
status.w_termsig = status.w_retcode = 0;
#else
status = 0;
#endif /* _POSIX_VERSION */
break;
}
else if (got_pid < 0 && errno != EINTR)
programming_error ("wait_for(%ld): %s", (long)pid, strerror(errno));
else if (got_pid > 0)
set_pid_status (got_pid, status);
}
if (got_pid > 0)
set_pid_status (got_pid, status);
#if defined (HAVE_WAITPID)
if (got_pid >= 0)
reap_zombie_children ();
#endif /* HAVE_WAITPID */
if (interactive_shell == 0)
{
SigHandler *temp_handler;
temp_handler = old_sigint_handler;
restore_sigint_handler ();
/* If the job exited because of SIGINT, make sure the shell acts as if
it had received one also. */
if (WIFSIGNALED (status) && (WTERMSIG (status) == SIGINT))
{
if (maybe_call_trap_handler (SIGINT) == 0)
{
if (temp_handler == SIG_DFL)
termsig_handler (SIGINT);
else if (temp_handler != INVALID_SIGNAL_HANDLER && temp_handler != SIG_IGN)
(*temp_handler) (SIGINT);
}
}
}
/* Default return value. */
/* ``a full 8 bits of status is returned'' */
return_val = process_exit_status (status);
last_command_exit_signal = get_termsig (status);
#if !defined (DONT_REPORT_SIGPIPE)
if ((WIFSTOPPED (status) == 0) && WIFSIGNALED (status) &&
(WTERMSIG (status) != SIGINT))
#else
if ((WIFSTOPPED (status) == 0) && WIFSIGNALED (status) &&
(WTERMSIG (status) != SIGINT) && (WTERMSIG (status) != SIGPIPE))
#endif
{
fprintf (stderr, "%s", j_strsignal (WTERMSIG (status)));
if (WIFCORED (status))
fprintf (stderr, _(" (core dumped)"));
fprintf (stderr, "\n");
}
if (interactive_shell && subshell_environment == 0)
{
if (WIFSIGNALED (status) || WIFSTOPPED (status))
set_tty_state ();
else
get_tty_state ();
}
return (return_val);
}
/* Send PID SIGNAL. Returns -1 on failure, 0 on success. If GROUP is non-zero,
or PID is less than -1, then kill the process group associated with PID. */
int
kill_pid (pid, signal, group)
pid_t pid;
int signal, group;
{
int result;
if (pid < -1)
{
pid = -pid;
group = 1;
}
result = group ? killpg (pid, signal) : kill (pid, signal);
return (result);
}
static TTYSTRUCT shell_tty_info;
static int got_tty_state;
/* Fill the contents of shell_tty_info with the current tty info. */
get_tty_state ()
{
int tty;
tty = input_tty ();
if (tty != -1)
{
ttgetattr (tty, &shell_tty_info);
got_tty_state = 1;
if (check_window_size)
get_new_window_size (0, (int *)0, (int *)0);
}
}
/* Make the current tty use the state in shell_tty_info. */
int
set_tty_state ()
{
int tty;
tty = input_tty ();
if (tty != -1)
{
if (got_tty_state == 0)
return 0;
ttsetattr (tty, &shell_tty_info);
}
return 0;
}
/* Give the terminal to PGRP. */
give_terminal_to (pgrp, force)
pid_t pgrp;
int force;
{
}
/* Stop a pipeline. */
int
stop_pipeline (async, ignore)
int async;
COMMAND *ignore;
{
already_making_children = 0;
return 0;
}
void
start_pipeline ()
{
already_making_children = 1;
}
void
stop_making_children ()
{
already_making_children = 0;
}
int
get_job_by_pid (pid, block)
pid_t pid;
int block;
{
int i;
i = find_index_by_pid (pid);
return ((i == NO_PID) ? PROC_BAD : i);
}
/* Print descriptive information about the job with leader pid PID. */
void
describe_pid (pid)
pid_t pid;
{
fprintf (stderr, "%ld\n", (long) pid);
}
void
freeze_jobs_list ()
{
}
void
unfreeze_jobs_list ()
{
}
int
count_all_jobs ()
{
return 0;
}
+1 -1
View File
@@ -1,4 +1,4 @@
BUILD_DIR=/usr/local/build/chet/bash/bash-current
BUILD_DIR=/usr/local/build/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
+4
View File
@@ -1,2 +1,6 @@
echo "warning: UNIX versions number signals and schedule processes differently." >&2
echo "warning: If output differing only in line numbers is produced, please" >&2
echo "warning: do not consider this a test failure." >&2
${THIS_SH} ./heredoc.tests > /tmp/xx 2>&1
diff /tmp/xx heredoc.right && rm -f /tmp/xx
+2
View File
@@ -0,0 +1,2 @@
${THIS_SH} ./heredoc.tests > /tmp/xx 2>&1
diff /tmp/xx heredoc.right && rm -f /tmp/xx