mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-27 15:43:18 +02:00
commit bash-20110525 snapshot
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+1057
File diff suppressed because it is too large
Load Diff
+1102
File diff suppressed because it is too large
Load Diff
+1087
File diff suppressed because it is too large
Load Diff
+58
-13
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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++;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
@@ -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 },
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
${THIS_SH} ./heredoc.tests > /tmp/xx 2>&1
|
||||
diff /tmp/xx heredoc.right && rm -f /tmp/xx
|
||||
Reference in New Issue
Block a user