mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-29 00:19:51 +02:00
commit bash-20060112 snapshot
This commit is contained in:
+119
-3
@@ -12712,9 +12712,6 @@ builtins/mkbuiltins.c
|
||||
set of default #defines based on a minimal POSIX system
|
||||
|
||||
jobs.c
|
||||
- change find_job to check jobs[i]->pipe as well as jobs[i] before
|
||||
trying to walk the pipeline -- should also check js.j_lastj in
|
||||
the for loop
|
||||
- change find_process to handle a NULL return value from find_pipeline
|
||||
- return immediately from delete_job if jobs[index] is already NULL or
|
||||
if it has a null pipeline associated with it
|
||||
@@ -12730,3 +12727,122 @@ doc/bash.1
|
||||
jobs.c
|
||||
- in realloc_jobs_list, make sure to zero out slots after j_lastj
|
||||
in the new list
|
||||
|
||||
1/9
|
||||
---
|
||||
support/mksignames.c
|
||||
- make sure to include <signal.h> to get right value of NSIG from
|
||||
(usually) <sys/signal.h>
|
||||
|
||||
1/10
|
||||
----
|
||||
parse.y
|
||||
- when calling parse_matched_pair on a $(...) command substitution,
|
||||
don't pass the P_DQUOTE flag so that single quotes don't get
|
||||
stripped from $'...' inside the command substitution. Bug report
|
||||
and fix from Mike Stroyan <mike.stroyan@hp.com>
|
||||
|
||||
jobs.c
|
||||
- start maintaining true count of living children in js.c_living
|
||||
- call reset_current in realloc_jobs_list, since old values for current
|
||||
and previous job are most likely incorrect
|
||||
- don't allocate a new list in realloc_jobs_list if the old size and
|
||||
new size are the same; just compact the existing list
|
||||
- make sure realloc_jobs_list updates value of js.j_njobs
|
||||
- add some more itrace messages about non-null jobs after j_lastj in
|
||||
jobs array
|
||||
|
||||
1/11
|
||||
----
|
||||
bashjmp.h
|
||||
- new value for second argument to longjmp: SIGEXIT. Reserved for
|
||||
future use
|
||||
|
||||
1/12
|
||||
----
|
||||
jobs.c
|
||||
- add logic to make_child to figure out when pids wrap around
|
||||
- turn second argument to delete_job into flags word, added flag to
|
||||
prevent adding proc to bgpids list
|
||||
|
||||
1/13
|
||||
----
|
||||
lib/readline/vi_mode.c
|
||||
- move code that moves forward a character out of rl_vi_append_mode
|
||||
into a separate function, _rl_vi_append_forward
|
||||
- change _rl_vi_append_mode to save `a' as the last command, so it
|
||||
can be redone properly
|
||||
- new function _rl_vi_backup, moves point back a character taking
|
||||
multibyte locales into account
|
||||
- change rl_vi_redo to handle redoing an `a' command specially --
|
||||
it should be redone like `i' but after moving forward a character
|
||||
- change rl_vi_redo to use _rl_vi_backup to move point backward
|
||||
after redoing `i' or `a'
|
||||
|
||||
jobs.c
|
||||
- new function, delete_old_job (pid), checks whether or not PID is in
|
||||
a job in the jobs list. If so, and the job is dead, it just removes
|
||||
the job from the list. If so, and the job is not dead, it zeros
|
||||
the pid in the appropriate PROCESS so pid aliasing doesn't occur
|
||||
- make_child calls delete_old_job to potentially remove an already-used
|
||||
instance of the pid just forked from the jobs list if pids have
|
||||
wrapped around. Finally fixes the bug reported by Tim Waugh
|
||||
<twaugh@redhat.com>
|
||||
|
||||
trap.c
|
||||
- new define, GETORIGSIG(sig), gets the original handling for SIG and
|
||||
sets SIG_HARD_IGNORE if that handler is SIG_IGN
|
||||
- call GETORIGSIG from initialize_traps, get_original_signal, and
|
||||
set_signal
|
||||
|
||||
jobs.c
|
||||
- in wait_for, if the original SIGINT handler is SIG_IGN, don't set
|
||||
the handler to wait_sigint_handler. This keeps scripts started in
|
||||
the background (and ignoring SIGINT) from dying due to SIGINT while
|
||||
they're waiting for a child to exit. Bug reported by Ingemar
|
||||
Nilsson <init@kth.se>
|
||||
|
||||
lib/readline/vi_mode.c
|
||||
- don't save text to buffer unless undo pointer points to a record of
|
||||
type UNDO_INSERT; zero it out instead. This fixes bug reported by
|
||||
Craig Turner <craig@synect.com> with redoing `ctd[ESC]' (empty
|
||||
insert after change to)
|
||||
|
||||
shell.c
|
||||
- change set_shell_name so invocations like "-/bin/bash" are marked as
|
||||
login shells
|
||||
|
||||
doc/bash.1
|
||||
- add note about destroying functions with `unset -f' to the section
|
||||
on shell functions
|
||||
|
||||
lib/readline/terminal.c
|
||||
- if readline hasn't been initialized (_rl_term_autowrap == -1, the
|
||||
value it's now initialized with), call _rl_init_terminal_io from
|
||||
_rl_set_screen_size before deciding whether or not to decrement
|
||||
_rl_screenwidth. Fixes bug from Mike Frysinger <vapier@gentoo.org>
|
||||
|
||||
1/14
|
||||
----
|
||||
lib/readline/input.c
|
||||
- allow rl_set_keyboard_input_timeout to set the timeout to 0, for
|
||||
applications that want to use select() like a poll without any
|
||||
waiting
|
||||
|
||||
lib/readline/doc/rltech.texi
|
||||
- documented valid values for timeout in rl_set_keyboard_input_timeout
|
||||
|
||||
jobs.c
|
||||
- in stop_pipeline, don't have the parent shell call give_terminal_to
|
||||
if subshell_environment contains SUBSHELL_ASYNC (no background
|
||||
process should ever give the terminal to anything other than
|
||||
shell_pgrp)
|
||||
- in make_child, don't give the terminal away if subshell_environment
|
||||
contains SUBSHELL_ASYNC
|
||||
|
||||
1/15
|
||||
----
|
||||
subst.c
|
||||
- in parameter_brace_expand, if extracting ${#varname}, only allow
|
||||
`}' to end the expansion, since none of the other expansions are
|
||||
valid. Fixes Debian bug reported by Jan Nordhorlz <jckn@gmx.net>
|
||||
|
||||
+123
-3
@@ -12712,9 +12712,6 @@ builtins/mkbuiltins.c
|
||||
set of default #defines based on a minimal POSIX system
|
||||
|
||||
jobs.c
|
||||
- change find_job to check jobs[i]->pipe as well as jobs[i] before
|
||||
trying to walk the pipeline -- should also check js.j_lastj in
|
||||
the for loop
|
||||
- change find_process to handle a NULL return value from find_pipeline
|
||||
- return immediately from delete_job if jobs[index] is already NULL or
|
||||
if it has a null pipeline associated with it
|
||||
@@ -12726,3 +12723,126 @@ jobs.c
|
||||
doc/bash.1
|
||||
- patch from Tim Waugh to replace some literal single quotes with
|
||||
\(aq, the groff special character for it
|
||||
|
||||
jobs.c
|
||||
- in realloc_jobs_list, make sure to zero out slots after j_lastj
|
||||
in the new list
|
||||
|
||||
1/9
|
||||
---
|
||||
support/mksignames.c
|
||||
- make sure to include <signal.h> to get right value of NSIG from
|
||||
(usually) <sys/signal.h>
|
||||
|
||||
1/10
|
||||
----
|
||||
parse.y
|
||||
- when calling parse_matched_pair on a $(...) command substitution,
|
||||
don't pass the P_DQUOTE flag so that single quotes don't get
|
||||
stripped from $'...' inside the command substitution. Bug report
|
||||
and fix from Mike Stroyan <mike.stroyan@hp.com>
|
||||
|
||||
jobs.c
|
||||
- start maintaining true count of living children in js.c_living
|
||||
- call reset_current in realloc_jobs_list, since old values for current
|
||||
and previous job are most likely incorrect
|
||||
- don't allocate a new list in realloc_jobs_list if the old size and
|
||||
new size are the same; just compact the existing list
|
||||
- make sure realloc_jobs_list updates value of js.j_njobs
|
||||
- add some more itrace messages about non-null jobs after j_lastj in
|
||||
jobs array
|
||||
|
||||
1/11
|
||||
----
|
||||
bashjmp.h
|
||||
- new value for second argument to longjmp: SIGEXIT. Reserved for
|
||||
future use
|
||||
|
||||
1/12
|
||||
----
|
||||
jobs.c
|
||||
- add logic to make_child to figure out when pids wrap around
|
||||
- turn second argument to delete_job into flags word, added flag to
|
||||
prevent adding proc to bgpids list
|
||||
|
||||
1/13
|
||||
----
|
||||
lib/readline/vi_mode.c
|
||||
- move code that moves forward a character out of rl_vi_append_mode
|
||||
into a separate function, _rl_vi_append_forward
|
||||
- change _rl_vi_append_mode to save `a' as the last command, so it
|
||||
can be redone properly
|
||||
- new function _rl_vi_backup, moves point back a character taking
|
||||
multibyte locales into account
|
||||
- change rl_vi_redo to handle redoing an `a' command specially --
|
||||
it should be redone like `i' but after moving forward a character
|
||||
- change rl_vi_redo to use _rl_vi_backup to move point backward
|
||||
after redoing `i' or `a'
|
||||
|
||||
jobs.c
|
||||
- new function, delete_old_job (pid), checks whether or not PID is in
|
||||
a job in the jobs list. If so, and the job is dead, it just removes
|
||||
the job from the list. If so, and the job is not dead, it zeros
|
||||
the pid in the appropriate PROCESS so pid aliasing doesn't occur
|
||||
- make_child calls delete_old_job to potentially remove an already-used
|
||||
instance of the pid just forked from the jobs list if pids have
|
||||
wrapped around. Finally fixes the bug reported by Tim Waugh
|
||||
<twaugh@redhat.com>
|
||||
|
||||
trap.c
|
||||
- new define, GETORIGSIG(sig), gets the original handling for SIG and
|
||||
sets SIG_HARD_IGNORE if that handler is SIG_IGN
|
||||
- call GETORIGSIG from initialize_traps, get_original_signal, and
|
||||
set_signal
|
||||
|
||||
jobs.c
|
||||
- in wait_for, if the original SIGINT handler is SIG_IGN, don't set
|
||||
the handler to wait_sigint_handler. This keeps scripts started in
|
||||
the background (and ignoring SIGINT) from dying due to SIGINT while
|
||||
they're waiting for a child to exit. Bug reported by Ingemar
|
||||
Nilsson <init@kth.se>
|
||||
|
||||
lib/readline/vi_mode.c
|
||||
- don't save text to buffer unless undo pointer points to a record of
|
||||
type UNDO_INSERT; zero it out instead. This fixes bug reported by
|
||||
Craig Turner <craig@synect.com> with redoing `ctd[ESC]' (empty
|
||||
insert after change to)
|
||||
|
||||
shell.c
|
||||
- change set_shell_name so invocations like "-/bin/bash" are marked as
|
||||
login shells
|
||||
|
||||
doc/bash.1
|
||||
- add note about destroying functions with `unset -f' to the section
|
||||
on shell functions
|
||||
|
||||
lib/readline/terminal.c
|
||||
- if readline hasn't been initialized (_rl_term_autowrap == -1, the
|
||||
value it's now initialized with), call _rl_init_terminal_io from
|
||||
_rl_set_screen_size before deciding whether or not to decrement
|
||||
_rl_screenwidth. Fixes bug from Mike Frysinger <vapier@gentoo.org>
|
||||
|
||||
1/14
|
||||
----
|
||||
lib/readline/input.c
|
||||
- allow rl_set_keyboard_input_timeout to set the timeout to 0, for
|
||||
applications that want to use select() like a poll without any
|
||||
waiting
|
||||
|
||||
lib/readline/doc/rltech.texi
|
||||
- documented valid values for timeout in rl_set_keyboard_input_timeout
|
||||
|
||||
jobs.c
|
||||
- in stop_pipeline, don't have the parent shell call give_terminal_to
|
||||
if subshell_environment contains SUBSHELL_ASYNC (no background
|
||||
process should ever give the terminal to anything other than
|
||||
shell_pgrp)
|
||||
- in make_child, don't give the terminal away if subshell_environment
|
||||
contains SUBSHELL_ASYNC
|
||||
|
||||
1/15
|
||||
----
|
||||
subst.c
|
||||
- in parameter_brace_expand, if extracting ${#varname}, only allow
|
||||
`}' to end the expansion, since none of the other expansions are
|
||||
valid
|
||||
|
||||
@@ -466,6 +466,8 @@ po/en@quot.po f
|
||||
po/en@boldquot.po f
|
||||
po/en@quot.gmo f
|
||||
po/en@boldquot.gmo f
|
||||
po/ru.po f
|
||||
po/ru.gmo f
|
||||
po/insert-header.sin f
|
||||
po/quot.sed f
|
||||
po/remove-potcdate.sin f
|
||||
|
||||
@@ -38,5 +38,6 @@ extern procenv_t return_catch; /* used by `return' builtin */
|
||||
#define DISCARD 2 /* Discard current command. */
|
||||
#define EXITPROG 3 /* Unconditionally exit the program now. */
|
||||
#define ERREXIT 4 /* Exit due to error condition */
|
||||
#define SIGEXIT 5 /* Exit due to fatal terminating signal */
|
||||
|
||||
#endif /* _BASHJMP_H_ */
|
||||
|
||||
+6
-2
@@ -6,12 +6,12 @@
|
||||
.\" Case Western Reserve University
|
||||
.\" chet@po.cwru.edu
|
||||
.\"
|
||||
.\" Last Change: Wed Dec 28 19:58:45 EST 2005
|
||||
.\" Last Change: Fri Jan 13 19:56:03 EST 2006
|
||||
.\"
|
||||
.\" bash_builtins, strip all but Built-Ins section
|
||||
.if \n(zZ=1 .ig zZ
|
||||
.if \n(zY=1 .ig zY
|
||||
.TH BASH 1 "2005 Dec 28" "GNU Bash-3.1"
|
||||
.TH BASH 1 "2006 Jan 13" "GNU Bash-3.2"
|
||||
.\"
|
||||
.\" There's some problem with having a `@'
|
||||
.\" in a tagged paragraph with the BSD man macros.
|
||||
@@ -3418,6 +3418,10 @@ automatically have them defined with the
|
||||
option to the
|
||||
.B export
|
||||
builtin.
|
||||
A function definition may be deleted using the \fB\-f\fP option to
|
||||
the
|
||||
.B unset
|
||||
builtin.
|
||||
Note that shell functions and variables with the same name may result
|
||||
in multiple identically-named entries in the environment passed to the
|
||||
shell's children.
|
||||
|
||||
+139
-438
File diff suppressed because it is too large
Load Diff
+15
-20
@@ -6,12 +6,12 @@
|
||||
.\" Case Western Reserve University
|
||||
.\" chet@po.cwru.edu
|
||||
.\"
|
||||
.\" Last Change: Mon Dec 19 09:04:39 EST 2005
|
||||
.\" Last Change: Wed Dec 28 19:58:45 EST 2005
|
||||
.\"
|
||||
.\" bash_builtins, strip all but Built-Ins section
|
||||
.if \n(zZ=1 .ig zZ
|
||||
.if \n(zY=1 .ig zY
|
||||
.TH BASH 1 "2005 Dec 19" "GNU Bash-3.1"
|
||||
.TH BASH 1 "2005 Dec 28" "GNU Bash-3.1"
|
||||
.\"
|
||||
.\" There's some problem with having a `@'
|
||||
.\" in a tagged paragraph with the BSD man macros.
|
||||
@@ -977,7 +977,7 @@ quotes (see
|
||||
.B PARAMETERS
|
||||
below).
|
||||
.PP
|
||||
Words of the form \fB$\fP'\fIstring\fP' are treated specially. The
|
||||
Words of the form \fB$\fP\(aq\fIstring\fP\(aq are treated specially. The
|
||||
word expands to \fIstring\fP, with backslash-escaped characters replaced
|
||||
as specified by the ANSI C standard. Backslash escape sequences, if
|
||||
present, are decoded as follows:
|
||||
@@ -1011,7 +1011,7 @@ vertical tab
|
||||
.B \e\e
|
||||
backslash
|
||||
.TP
|
||||
.B \e'
|
||||
.B \e\(aq
|
||||
single quote
|
||||
.TP
|
||||
.B \e\fInnn\fP
|
||||
@@ -1845,7 +1845,7 @@ the current mailfile.
|
||||
Example:
|
||||
.RS
|
||||
.PP
|
||||
\fBMAILPATH\fP='/var/mail/bfox?"You have mail":~/shell\-mail?"$_ has mail!"'
|
||||
\fBMAILPATH\fP=\(aq/var/mail/bfox?"You have mail":~/shell\-mail?"$_ has mail!"\(aq
|
||||
.PP
|
||||
.B Bash
|
||||
supplies a default value for this variable, but the location of the user
|
||||
@@ -1979,7 +1979,7 @@ The value of \fIp\fP determines whether or not the fraction is
|
||||
included.
|
||||
.IP
|
||||
If this variable is not set, \fBbash\fP acts as if it had the
|
||||
value \fB$'\enreal\et%3lR\enuser\et%3lU\ensys\t%3lS'\fP.
|
||||
value \fB$\(aq\enreal\et%3lR\enuser\et%3lU\ensys\t%3lS\(aq\fP.
|
||||
If the value is null, no timing information is displayed.
|
||||
A trailing newline is added when the format string is displayed.
|
||||
.TP
|
||||
@@ -2531,17 +2531,12 @@ the pattern removal operation is applied to each member of the
|
||||
array in turn, and the expansion is the resultant list.
|
||||
.TP
|
||||
${\fIparameter\fP\fB/\fP\fIpattern\fP\fB/\fP\fIstring\fP}
|
||||
.PD 0
|
||||
.TP
|
||||
${\fIparameter\fP\fB//\fP\fIpattern\fP\fB/\fP\fIstring\fP}
|
||||
.PD
|
||||
The \fIpattern\fP is expanded to produce a pattern just as in
|
||||
pathname expansion.
|
||||
\fIParameter\fP is expanded and the longest match of \fIpattern\fP
|
||||
against its value is replaced with \fIstring\fP.
|
||||
In the first form, only the first match is replaced.
|
||||
The second form causes all matches of \fIpattern\fP to be
|
||||
replaced with \fIstring\fP.
|
||||
If \Ipattern\fP begins with \fB/\fP, all matches of \fIpattern\fP are
|
||||
replaced with \fIstring\fP. Normally only the first match is replaced.
|
||||
If \fIpattern\fP begins with \fB#\fP, it must match at the beginning
|
||||
of the expanded value of \fIparameter\fP.
|
||||
If \fIpattern\fP begins with \fB%\fP, it must match at the end
|
||||
@@ -2708,7 +2703,7 @@ If the value of
|
||||
.B IFS
|
||||
is null, no word splitting occurs.
|
||||
.PP
|
||||
Explicit null arguments (\^\f3"\^"\fP or \^\f3'\^'\fP\^) are retained.
|
||||
Explicit null arguments (\^\f3"\^"\fP or \^\f3\(aq\^\(aq\fP\^) are retained.
|
||||
Unquoted implicit null arguments, resulting from the expansion of
|
||||
parameters that have no values, are removed.
|
||||
If a parameter with no value is expanded within double quotes, a
|
||||
@@ -2930,7 +2925,7 @@ Matches anything except one of the given patterns
|
||||
After the preceding expansions, all unquoted occurrences of the
|
||||
characters
|
||||
.BR \e ,
|
||||
.BR ' ,
|
||||
.BR \(aq ,
|
||||
and \^\f3"\fP\^ that did not result from one of the above
|
||||
expansions are removed.
|
||||
.SH REDIRECTION
|
||||
@@ -4495,8 +4490,8 @@ backslash
|
||||
.B \e"
|
||||
literal "
|
||||
.TP
|
||||
.B \e'
|
||||
literal '
|
||||
.B \e\(aq
|
||||
literal \(aq
|
||||
.RE
|
||||
.PD
|
||||
.PP
|
||||
@@ -4544,7 +4539,7 @@ be used to indicate a macro definition.
|
||||
Unquoted text is assumed to be a function name.
|
||||
In the macro body, the backslash escapes described above are expanded.
|
||||
Backslash will quote any other character in the macro text,
|
||||
including " and '.
|
||||
including " and \(aq.
|
||||
.PP
|
||||
.B Bash
|
||||
allows the current readline key bindings to be displayed or modified
|
||||
@@ -7320,7 +7315,7 @@ format specifications, each of which causes printing of the next successive
|
||||
In addition to the standard \fIprintf\fP(1) formats, \fB%b\fP causes
|
||||
\fBprintf\fP to expand backslash escape sequences in the corresponding
|
||||
\fIargument\fP (except that \fB\ec\fP terminates output, backslashes in
|
||||
\fB\e'\fP, \fB\e"\fP, and \fB\e?\fP are not removed, and octal escapes
|
||||
\fB\e\(aq\fP, \fB\e"\fP, and \fB\e?\fP are not removed, and octal escapes
|
||||
beginning with \fB\e0\fP may contain up to four digits),
|
||||
and \fB%q\fP causes \fBprintf\fP to output the corresponding
|
||||
\fIargument\fP in a format that can be reused as shell input.
|
||||
@@ -8037,7 +8032,7 @@ If set, the extended pattern matching features described above under
|
||||
\fBPathname Expansion\fP are enabled.
|
||||
.TP 8
|
||||
.B extquote
|
||||
If set, \fB$\fP'\fIstring\fP' and \fB$\fP"\fIstring\fP" quoting is
|
||||
If set, \fB$\fP\(aq\fIstring\fP\(aq and \fB$\fP"\fIstring\fP" quoting is
|
||||
performed within \fB${\fP\fIparameter\fP\fB}\fP expansions
|
||||
enclosed in double quotes. This option is enabled by default.
|
||||
.TP 8
|
||||
|
||||
+4
-1
@@ -1084,6 +1084,9 @@ name of a command.
|
||||
Any redirections (@pxref{Redirections}) associated with the shell function
|
||||
are performed when the function is executed.
|
||||
|
||||
A function definition may be deleted using the @option{-f} option to the
|
||||
@code{unset} builtin (@pxref{Bourne Shell Builtins}).
|
||||
|
||||
The exit status of a function definition is zero unless a syntax error
|
||||
occurs or a readonly function with the same name already exists.
|
||||
When executed, the exit status of a function is the exit status of the
|
||||
@@ -2807,7 +2810,7 @@ If @code{getopts} is silent, then a colon (@samp{:}) is placed in
|
||||
@item hash
|
||||
@btindex hash
|
||||
@example
|
||||
hash [-'r] [-p @var{filename}] [-dt] [@var{name}]
|
||||
hash [-r] [-p @var{filename}] [-dt] [@var{name}]
|
||||
@end example
|
||||
Remember the full pathnames of commands specified as @var{name} arguments,
|
||||
so they need not be searched for on subsequent invocations.
|
||||
|
||||
+3
-3
@@ -2596,7 +2596,7 @@ the command directly, without invoking another program.
|
||||
Builtin commands are necessary to implement functionality impossible
|
||||
or inconvenient to obtain with separate utilities.
|
||||
|
||||
This section briefly the builtins which Bash inherits from
|
||||
This section briefly describes the builtins which Bash inherits from
|
||||
the Bourne Shell, as well as the builtin commands which are unique
|
||||
to or have been extended in Bash.
|
||||
|
||||
@@ -4102,8 +4102,8 @@ shell will exit.
|
||||
Print shell input lines as they are read.
|
||||
|
||||
@item -x
|
||||
Print a trace of simple commands, \fBfor\fP commands, \fBcase\fP
|
||||
commands, \fBselect\fP commands, and arithmetic \fBfor\fP commands
|
||||
Print a trace of simple commands, @code{for} commands, @code{case}
|
||||
commands, @code{select} commands, and arithmetic @code{for} commands
|
||||
and their arguments or associated word lists after they are
|
||||
expanded and before they are executed. The value of the @env{PS4}
|
||||
variable is expanded and the resultant value is printed before
|
||||
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
@ignore
|
||||
Copyright (C) 1988-2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-2006 Free Software Foundation, Inc.
|
||||
@end ignore
|
||||
|
||||
@set LASTCHANGE Fri Dec 30 10:50:51 EST 2005
|
||||
@set LASTCHANGE Fri Jan 13 19:55:29 EST 2006
|
||||
|
||||
@set EDITION 3.1
|
||||
@set VERSION 3.1
|
||||
@set UPDATED 30 December 2005
|
||||
@set UPDATED-MONTH December 2005
|
||||
@set UPDATED 13 January 2006
|
||||
@set UPDATED-MONTH January 2006
|
||||
|
||||
+2
-2
@@ -2,9 +2,9 @@
|
||||
Copyright (C) 1988-2005 Free Software Foundation, Inc.
|
||||
@end ignore
|
||||
|
||||
@set LASTCHANGE Wed Dec 28 19:59:13 EST 2005
|
||||
@set LASTCHANGE Fri Dec 30 10:50:51 EST 2005
|
||||
|
||||
@set EDITION 3.1
|
||||
@set VERSION 3.1
|
||||
@set UPDATED 28 December 2005
|
||||
@set UPDATED 30 December 2005
|
||||
@set UPDATED-MONTH December 2005
|
||||
|
||||
+6
-1
@@ -2396,6 +2396,7 @@ execute_arith_command (arith_command)
|
||||
int expok, save_line_number, retval;
|
||||
intmax_t expresult;
|
||||
WORD_LIST *new;
|
||||
char *exp;
|
||||
|
||||
expresult = 0;
|
||||
|
||||
@@ -2438,8 +2439,11 @@ execute_arith_command (arith_command)
|
||||
|
||||
if (new)
|
||||
{
|
||||
expresult = evalexp (new->word->word, &expok);
|
||||
exp = new->next ? string_list (new) : new->word->word;
|
||||
expresult = evalexp (exp, &expok);
|
||||
line_number = save_line_number;
|
||||
if (exp != new->word->word)
|
||||
free (exp);
|
||||
dispose_words (new);
|
||||
}
|
||||
else
|
||||
@@ -2621,6 +2625,7 @@ execute_null_command (redirects, pipe_in, pipe_out, async)
|
||||
{
|
||||
int r;
|
||||
|
||||
itrace("execute_null_command: async = %d subshell_environment = %d", async, subshell_environment);
|
||||
if (pipe_in != NO_PIPE || pipe_out != NO_PIPE || async)
|
||||
{
|
||||
/* We have a null command, but we really want a subshell to take
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/* This file works with both POSIX and BSD systems. It implements job
|
||||
control. */
|
||||
|
||||
/* Copyright (C) 1989-2005 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1989-2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -77,7 +77,15 @@ extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
#define DEFAULT_CHILD_MAX 32
|
||||
#define MAX_JOBS_IN_ARRAY 4096 /* testing */
|
||||
#if 1
|
||||
#define MAX_JOBS_IN_ARRAY 4096 /* production*/
|
||||
#else
|
||||
#define MAX_JOBS_IN_ARRAY 128 /* testing */
|
||||
#endif
|
||||
|
||||
/* Flag values for second argument to delete_job */
|
||||
#define DEL_WARNSTOPPED 1 /* warn about deleting stopped jobs */
|
||||
#define DEL_NOBGPID 2 /* don't add pgrp leader to bgpids */
|
||||
|
||||
/* Take care of system dependencies that must be handled when waiting for
|
||||
children. The arguments to the WAITPID macro match those to the Posix.1
|
||||
@@ -307,6 +315,10 @@ static int jobs_list_frozen;
|
||||
|
||||
static char retcode_name_buffer[64];
|
||||
|
||||
/* flags to detect pid wraparound */
|
||||
static pid_t first_pid = NO_PID;
|
||||
static int pid_wrap = -1;
|
||||
|
||||
#if !defined (_POSIX_VERSION)
|
||||
|
||||
/* These are definitions to map POSIX 1003.1 functions onto existing BSD
|
||||
@@ -328,11 +340,13 @@ tcgetpgrp (fd)
|
||||
|
||||
#endif /* !_POSIX_VERSION */
|
||||
|
||||
/* Initialize the global job stats structure. */
|
||||
/* Initialize the global job stats structure and other bookkeeping variables */
|
||||
void
|
||||
init_job_stats ()
|
||||
{
|
||||
js = zerojs;
|
||||
first_pid = NO_PID;
|
||||
pid_wrap = -1;
|
||||
}
|
||||
|
||||
/* Return the working directory for the current process. Unlike
|
||||
@@ -619,8 +633,11 @@ stop_pipeline (async, deferred)
|
||||
* once in the parent and once in each child. This is where
|
||||
* the parent gives it away.
|
||||
*
|
||||
* Don't give the terminal away if this shell is an asynchronous
|
||||
* subshell.
|
||||
*
|
||||
*/
|
||||
if (job_control && newjob->pgrp)
|
||||
if (job_control && newjob->pgrp && (subshell_environment&SUBSHELL_ASYNC) == 0)
|
||||
give_terminal_to (newjob->pgrp, 0);
|
||||
}
|
||||
}
|
||||
@@ -805,12 +822,14 @@ cleanup_dead_jobs ()
|
||||
|
||||
QUEUE_SIGCHLD(os);
|
||||
|
||||
/* XXX could use js.j_firstj here */
|
||||
/* XXX could use js.j_firstj and js.j_lastj here */
|
||||
for (i = 0; i < js.j_jobslots; i++)
|
||||
{
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("cleanup_dead_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
|
||||
if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i))
|
||||
@@ -837,6 +856,30 @@ processes_in_job (job)
|
||||
return nproc;
|
||||
}
|
||||
|
||||
static void
|
||||
delete_old_job (pid)
|
||||
pid_t pid;
|
||||
{
|
||||
PROCESS *p;
|
||||
int job;
|
||||
|
||||
job = find_job (pid, 0, &p);
|
||||
if (job != NO_JOB)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
itrace ("delete_old_job: found pid %d in job %d with state %d", pid, job, jobs[job]->state);
|
||||
#endif
|
||||
if (JOBSTATE (job) == JDEAD)
|
||||
delete_job (job, DEL_NOBGPID);
|
||||
else
|
||||
{
|
||||
internal_warning (_("forked pid %d appears in running job %d"), pid, job);
|
||||
if (p)
|
||||
p->pid = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reallocate and compress the jobs list. This returns with a jobs array
|
||||
whose size is a multiple of JOB_SLOTS and can hold the current number of
|
||||
jobs. Heuristics are used to minimize the number of new reallocs. */
|
||||
@@ -844,9 +887,10 @@ static void
|
||||
realloc_jobs_list ()
|
||||
{
|
||||
sigset_t set, oset;
|
||||
int nsize, i, j;
|
||||
int nsize, i, j, ncur, nprev;
|
||||
JOB **nlist;
|
||||
|
||||
ncur = nprev = NO_JOB;
|
||||
nsize = ((js.j_njobs + JOB_SLOTS - 1) / JOB_SLOTS);
|
||||
nsize *= JOB_SLOTS;
|
||||
i = js.j_njobs % JOB_SLOTS;
|
||||
@@ -854,21 +898,51 @@ realloc_jobs_list ()
|
||||
nsize += JOB_SLOTS;
|
||||
|
||||
BLOCK_CHILD (set, oset);
|
||||
nlist = (JOB **) xmalloc (nsize * sizeof (JOB *));
|
||||
nlist = (js.j_jobslots == nsize) ? jobs : (JOB **) xmalloc (nsize * sizeof (JOB *));
|
||||
|
||||
for (i = j = 0; i < js.j_jobslots; i++)
|
||||
if (jobs[i])
|
||||
nlist[j++] = jobs[i];
|
||||
{
|
||||
if (i == js.j_current)
|
||||
ncur = j;
|
||||
if (i == js.j_previous)
|
||||
nprev = j;
|
||||
nlist[j++] = jobs[i];
|
||||
}
|
||||
|
||||
#if defined (DEBUG)
|
||||
itrace ("realloc_jobs_list: resize jobs list from %d to %d", js.j_jobslots, nsize);
|
||||
itrace ("realloc_jobs_list: j_lastj changed from %d to %d", js.j_lastj, (j > 0) ? j - 1 : 0);
|
||||
itrace ("realloc_jobs_list: j_njobs changed from %d to %d", js.j_njobs, (j > 0) ? j - 1 : 0);
|
||||
#endif
|
||||
|
||||
js.j_firstj = 0;
|
||||
js.j_lastj = (j > 0) ? j - 1: 0;
|
||||
js.j_lastj = (j > 0) ? j - 1 : 0;
|
||||
js.j_njobs = j;
|
||||
js.j_jobslots = nsize;
|
||||
|
||||
/* Zero out remaining slots in new jobs list */
|
||||
for ( ; j < nsize; j++)
|
||||
jobs[j] = (JOB *)NULL;
|
||||
nlist[j] = (JOB *)NULL;
|
||||
|
||||
free (jobs);
|
||||
jobs = nlist;
|
||||
if (jobs != nlist)
|
||||
{
|
||||
free (jobs);
|
||||
jobs = nlist;
|
||||
}
|
||||
|
||||
if (ncur != NO_JOB)
|
||||
js.j_current = ncur;
|
||||
if (nprev != NO_JOB)
|
||||
js.j_previous = nprev;
|
||||
|
||||
/* Need to reset these */
|
||||
if (js.j_current == NO_JOB || js.j_previous == NO_JOB || js.j_current > js.j_lastj || js.j_previous > js.j_lastj)
|
||||
reset_current ();
|
||||
|
||||
#ifdef DEBUG
|
||||
itrace ("realloc_jobs_list: reset js.j_current (%d) and js.j_previous (%d)", js.j_current, js.j_previous);
|
||||
#endif
|
||||
|
||||
UNBLOCK_CHILD (oset);
|
||||
}
|
||||
@@ -877,7 +951,7 @@ realloc_jobs_list ()
|
||||
the jobs array to some predefined maximum. Called when the shell is not
|
||||
the foreground process (subshell_environment != 0). Returns the first
|
||||
available slot in the compacted list. If that value is js.j_jobslots, then
|
||||
the list needs to be reallocated. The jobs array is in new memory if
|
||||
the list needs to be reallocated. The jobs array may be in new memory if
|
||||
this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */
|
||||
static int
|
||||
compact_jobs_list (flags)
|
||||
@@ -888,15 +962,15 @@ compact_jobs_list (flags)
|
||||
|
||||
reap_dead_jobs ();
|
||||
realloc_jobs_list ();
|
||||
|
||||
|
||||
return (js.j_lastj);
|
||||
}
|
||||
|
||||
/* Delete the job at INDEX from the job list. Must be called
|
||||
with SIGCHLD blocked. */
|
||||
void
|
||||
delete_job (job_index, warn_stopped)
|
||||
int job_index, warn_stopped;
|
||||
delete_job (job_index, dflags)
|
||||
int job_index, dflags;
|
||||
{
|
||||
register JOB *temp;
|
||||
PROCESS *proc;
|
||||
@@ -906,18 +980,21 @@ delete_job (job_index, warn_stopped)
|
||||
if (js.j_jobslots == 0 || jobs_list_frozen)
|
||||
return;
|
||||
|
||||
if (warn_stopped && subshell_environment == 0 && STOPPED (job_index))
|
||||
if ((dflags & DEL_WARNSTOPPED) && subshell_environment == 0 && STOPPED (job_index))
|
||||
internal_warning (_("deleting stopped job %d with process group %ld"), job_index+1, (long)jobs[job_index]->pgrp);
|
||||
temp = jobs[job_index];
|
||||
if (temp == 0 || temp->pipe == 0)
|
||||
if (temp == 0)
|
||||
return;
|
||||
if (job_index == js.j_current || job_index == js.j_previous)
|
||||
reset_current ();
|
||||
|
||||
proc = find_last_proc (job_index, 0);
|
||||
/* Could do this just for J_ASYNC jobs, but we save all. */
|
||||
if (proc)
|
||||
bgp_add (proc->pid, process_exit_status (proc->status));
|
||||
if ((dflags & DEL_NOBGPID) == 0)
|
||||
{
|
||||
proc = find_last_proc (job_index, 0);
|
||||
/* Could do this just for J_ASYNC jobs, but we save all. */
|
||||
if (proc)
|
||||
bgp_add (proc->pid, process_exit_status (proc->status));
|
||||
}
|
||||
|
||||
jobs[job_index] = (JOB *)NULL;
|
||||
if (temp == js.j_lastmade)
|
||||
@@ -1097,6 +1174,8 @@ map_over_jobs (func, arg1, arg2)
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("map_over_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
if (jobs[i])
|
||||
{
|
||||
@@ -1235,8 +1314,10 @@ find_job (pid, alive_only, procp)
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("find_job: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
if (jobs[i] && jobs[i]->pipe)
|
||||
if (jobs[i])
|
||||
{
|
||||
p = jobs[i]->pipe;
|
||||
|
||||
@@ -1661,7 +1742,7 @@ make_child (command, async_p)
|
||||
In this case, we don't want to give the terminal to the
|
||||
shell's process group (we could be in the middle of a
|
||||
pipeline, for example). */
|
||||
if (async_p == 0 && pipeline_pgrp != shell_pgrp)
|
||||
if (async_p == 0 && pipeline_pgrp != shell_pgrp && ((subshell_environment&SUBSHELL_ASYNC) == 0))
|
||||
give_terminal_to (pipeline_pgrp, 0);
|
||||
|
||||
#if defined (PGRP_PIPE)
|
||||
@@ -1703,6 +1784,13 @@ make_child (command, async_p)
|
||||
/* In the parent. Remember the pid of the child just created
|
||||
as the proper pgrp if this is the first child. */
|
||||
|
||||
if (first_pid == NO_PID)
|
||||
first_pid = pid;
|
||||
else if (pid_wrap == -1 && pid < first_pid)
|
||||
pid_wrap = 0;
|
||||
else if (pid_wrap == 0 && pid >= first_pid)
|
||||
pid_wrap = 1;
|
||||
|
||||
if (job_control)
|
||||
{
|
||||
if (pipeline_pgrp == 0)
|
||||
@@ -1736,6 +1824,9 @@ make_child (command, async_p)
|
||||
last_asynchronous_pid = 1;
|
||||
#endif
|
||||
|
||||
if (pid_wrap > 0)
|
||||
delete_old_job (pid);
|
||||
|
||||
#if !defined (RECYCLES_PIDS)
|
||||
/* Only check for saved status if we've saved more than CHILD_MAX
|
||||
statuses, unless the system recycles pids. */
|
||||
@@ -2004,12 +2095,14 @@ wait_for_background_pids ()
|
||||
BLOCK_CHILD (set, oset);
|
||||
|
||||
/* find first running job; if none running in foreground, break */
|
||||
/* XXX could use js.j_firstj here */
|
||||
/* XXX could use js.j_firstj and js.j_lastj here */
|
||||
for (i = 0; i < js.j_jobslots; i++)
|
||||
{
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("wait_for_background_pids: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("wait_for_background_pids: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0)
|
||||
break;
|
||||
@@ -2204,7 +2297,11 @@ wait_for (pid)
|
||||
/* This is possibly a race condition -- should it go in stop_pipeline? */
|
||||
wait_sigint_received = 0;
|
||||
if (job_control == 0)
|
||||
old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler);
|
||||
{
|
||||
old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler);
|
||||
if (old_sigint_handler == SIG_IGN)
|
||||
set_signal_handler (SIGINT, old_sigint_handler);
|
||||
}
|
||||
|
||||
termination_state = last_command_exit_value;
|
||||
|
||||
@@ -2271,6 +2368,7 @@ wait_for (pid)
|
||||
{
|
||||
child->running = PS_DONE;
|
||||
child->status = 0; /* XXX -- can't find true status */
|
||||
js.c_living = 0; /* no living child processes */
|
||||
if (job != NO_JOB)
|
||||
{
|
||||
jobs[job]->state = JDEAD;
|
||||
@@ -2322,7 +2420,6 @@ wait_for (pid)
|
||||
if (job == NO_JOB)
|
||||
itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)", (long)shell_pgrp);
|
||||
#endif
|
||||
|
||||
give_terminal_to (shell_pgrp, 0);
|
||||
}
|
||||
|
||||
@@ -2903,7 +3000,10 @@ waitchld (wpid, block)
|
||||
/* 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)
|
||||
children_exited++;
|
||||
{
|
||||
children_exited++;
|
||||
js.c_living--;
|
||||
}
|
||||
|
||||
/* Locate our PROCESS for this pid. */
|
||||
child = find_process (pid, 1, &job); /* want living procs only */
|
||||
@@ -3643,9 +3743,11 @@ delete_all_jobs (running_only)
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("delete_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i))))
|
||||
delete_job (i, 1);
|
||||
delete_job (i, DEL_WARNSTOPPED);
|
||||
}
|
||||
if (running_only == 0)
|
||||
{
|
||||
@@ -3697,6 +3799,8 @@ count_all_jobs ()
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("count_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
if (jobs[i] && DEADJOB(i) == 0)
|
||||
n++;
|
||||
@@ -3770,6 +3874,8 @@ mark_dead_jobs_as_notified (force)
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
if (jobs[i] && DEADJOB (i))
|
||||
{
|
||||
@@ -3821,6 +3927,8 @@ itrace("mark_dead_jobs_as_notified: child_max = %d ndead = %d ndeadproc = %d", j
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
/* If marking this job as notified would drop us down below
|
||||
child_max, don't mark it so we can keep at least child_max
|
||||
|
||||
+4053
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
/* This file works with both POSIX and BSD systems. It implements job
|
||||
control. */
|
||||
|
||||
/* Copyright (C) 1989-2005 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1989-2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -77,7 +77,15 @@ extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
#define DEFAULT_CHILD_MAX 32
|
||||
#define MAX_JOBS_IN_ARRAY 4096 /* testing */
|
||||
#if 1
|
||||
#define MAX_JOBS_IN_ARRAY 4096 /* production*/
|
||||
#else
|
||||
#define MAX_JOBS_IN_ARRAY 128 /* testing */
|
||||
#endif
|
||||
|
||||
/* Flag values for second argument to delete_job */
|
||||
#define DEL_WARNSTOPPED 1 /* warn about deleting stopped jobs */
|
||||
#define DEL_NOBGPID 2 /* don't add pgrp leader to bgpids */
|
||||
|
||||
/* Take care of system dependencies that must be handled when waiting for
|
||||
children. The arguments to the WAITPID macro match those to the Posix.1
|
||||
@@ -307,6 +315,10 @@ static int jobs_list_frozen;
|
||||
|
||||
static char retcode_name_buffer[64];
|
||||
|
||||
/* flags to detect pid wraparound */
|
||||
static pid_t first_pid = NO_PID;
|
||||
static int pid_wrap = -1;
|
||||
|
||||
#if !defined (_POSIX_VERSION)
|
||||
|
||||
/* These are definitions to map POSIX 1003.1 functions onto existing BSD
|
||||
@@ -328,11 +340,13 @@ tcgetpgrp (fd)
|
||||
|
||||
#endif /* !_POSIX_VERSION */
|
||||
|
||||
/* Initialize the global job stats structure. */
|
||||
/* Initialize the global job stats structure and other bookkeeping variables */
|
||||
void
|
||||
init_job_stats ()
|
||||
{
|
||||
js = zerojs;
|
||||
first_pid = NO_PID;
|
||||
pid_wrap = -1;
|
||||
}
|
||||
|
||||
/* Return the working directory for the current process. Unlike
|
||||
@@ -619,8 +633,11 @@ stop_pipeline (async, deferred)
|
||||
* once in the parent and once in each child. This is where
|
||||
* the parent gives it away.
|
||||
*
|
||||
* Don't give the terminal away if this shell is an asynchronous
|
||||
* subshell.
|
||||
*
|
||||
*/
|
||||
if (job_control && newjob->pgrp)
|
||||
if (job_control && newjob->pgrp && (subshell_environment&SUBSHELL_ASYNC) == 0)
|
||||
give_terminal_to (newjob->pgrp, 0);
|
||||
}
|
||||
}
|
||||
@@ -805,12 +822,14 @@ cleanup_dead_jobs ()
|
||||
|
||||
QUEUE_SIGCHLD(os);
|
||||
|
||||
/* XXX could use js.j_firstj here */
|
||||
/* XXX could use js.j_firstj and js.j_lastj here */
|
||||
for (i = 0; i < js.j_jobslots; i++)
|
||||
{
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("cleanup_dead_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
|
||||
if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i))
|
||||
@@ -837,6 +856,30 @@ processes_in_job (job)
|
||||
return nproc;
|
||||
}
|
||||
|
||||
static void
|
||||
delete_old_job (pid)
|
||||
pid_t pid;
|
||||
{
|
||||
PROCESS *p;
|
||||
int job;
|
||||
|
||||
job = find_job (pid, 0, &p);
|
||||
if (job != NO_JOB)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
itrace ("delete_old_job: found pid %d in job %d with state %d", pid, job, jobs[job]->state);
|
||||
#endif
|
||||
if (JOBSTATE (job) == JDEAD)
|
||||
delete_job (job, DEL_NOBGPID);
|
||||
else
|
||||
{
|
||||
internal_warning (_("forked pid %d appears in running job %d"), pid, job);
|
||||
if (p)
|
||||
p->pid = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reallocate and compress the jobs list. This returns with a jobs array
|
||||
whose size is a multiple of JOB_SLOTS and can hold the current number of
|
||||
jobs. Heuristics are used to minimize the number of new reallocs. */
|
||||
@@ -844,9 +887,10 @@ static void
|
||||
realloc_jobs_list ()
|
||||
{
|
||||
sigset_t set, oset;
|
||||
int nsize, i, j;
|
||||
int nsize, i, j, ncur, nprev;
|
||||
JOB **nlist;
|
||||
|
||||
ncur = nprev = NO_JOB;
|
||||
nsize = ((js.j_njobs + JOB_SLOTS - 1) / JOB_SLOTS);
|
||||
nsize *= JOB_SLOTS;
|
||||
i = js.j_njobs % JOB_SLOTS;
|
||||
@@ -854,17 +898,51 @@ realloc_jobs_list ()
|
||||
nsize += JOB_SLOTS;
|
||||
|
||||
BLOCK_CHILD (set, oset);
|
||||
nlist = (JOB **) xmalloc (nsize * sizeof (JOB *));
|
||||
nlist = (js.j_jobslots == nsize) ? jobs : (JOB **) xmalloc (nsize * sizeof (JOB *));
|
||||
|
||||
for (i = j = 0; i < js.j_jobslots; i++)
|
||||
if (jobs[i])
|
||||
nlist[j++] = jobs[i];
|
||||
{
|
||||
if (i == js.j_current)
|
||||
ncur = j;
|
||||
if (i == js.j_previous)
|
||||
nprev = j;
|
||||
nlist[j++] = jobs[i];
|
||||
}
|
||||
|
||||
#if defined (DEBUG)
|
||||
itrace ("realloc_jobs_list: resize jobs list from %d to %d", js.j_jobslots, nsize);
|
||||
itrace ("realloc_jobs_list: j_lastj changed from %d to %d", js.j_lastj, (j > 0) ? j - 1 : 0);
|
||||
itrace ("realloc_jobs_list: j_njobs changed from %d to %d", js.j_njobs, (j > 0) ? j - 1 : 0);
|
||||
#endif
|
||||
|
||||
js.j_firstj = 0;
|
||||
js.j_lastj = (j > 0) ? j - 1: 0;
|
||||
js.j_lastj = (j > 0) ? j - 1 : 0;
|
||||
js.j_njobs = j;
|
||||
js.j_jobslots = nsize;
|
||||
|
||||
free (jobs);
|
||||
jobs = nlist;
|
||||
/* Zero out remaining slots in new jobs list */
|
||||
for ( ; j < nsize; j++)
|
||||
nlist[j] = (JOB *)NULL;
|
||||
|
||||
if (jobs != nlist)
|
||||
{
|
||||
free (jobs);
|
||||
jobs = nlist;
|
||||
}
|
||||
|
||||
if (ncur != NO_JOB)
|
||||
js.j_current = ncur;
|
||||
if (nprev != NO_JOB)
|
||||
js.j_previous = nprev;
|
||||
|
||||
/* Need to reset these */
|
||||
if (js.j_current == NO_JOB || js.j_previous == NO_JOB || js.j_current > js.j_lastj || js.j_previous > js.j_lastj)
|
||||
reset_current ();
|
||||
|
||||
#ifdef DEBUG
|
||||
itrace ("realloc_jobs_list: reset js.j_current (%d) and js.j_previous (%d)", js.j_current, js.j_previous);
|
||||
#endif
|
||||
|
||||
UNBLOCK_CHILD (oset);
|
||||
}
|
||||
@@ -873,7 +951,7 @@ realloc_jobs_list ()
|
||||
the jobs array to some predefined maximum. Called when the shell is not
|
||||
the foreground process (subshell_environment != 0). Returns the first
|
||||
available slot in the compacted list. If that value is js.j_jobslots, then
|
||||
the list needs to be reallocated. The jobs array is in new memory if
|
||||
the list needs to be reallocated. The jobs array may be in new memory if
|
||||
this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */
|
||||
static int
|
||||
compact_jobs_list (flags)
|
||||
@@ -884,15 +962,15 @@ compact_jobs_list (flags)
|
||||
|
||||
reap_dead_jobs ();
|
||||
realloc_jobs_list ();
|
||||
|
||||
|
||||
return (js.j_lastj);
|
||||
}
|
||||
|
||||
/* Delete the job at INDEX from the job list. Must be called
|
||||
with SIGCHLD blocked. */
|
||||
void
|
||||
delete_job (job_index, warn_stopped)
|
||||
int job_index, warn_stopped;
|
||||
delete_job (job_index, dflags)
|
||||
int job_index, dflags;
|
||||
{
|
||||
register JOB *temp;
|
||||
PROCESS *proc;
|
||||
@@ -902,18 +980,21 @@ delete_job (job_index, warn_stopped)
|
||||
if (js.j_jobslots == 0 || jobs_list_frozen)
|
||||
return;
|
||||
|
||||
if (warn_stopped && subshell_environment == 0 && STOPPED (job_index))
|
||||
if ((dflags & DEL_WARNSTOPPED) && subshell_environment == 0 && STOPPED (job_index))
|
||||
internal_warning (_("deleting stopped job %d with process group %ld"), job_index+1, (long)jobs[job_index]->pgrp);
|
||||
temp = jobs[job_index];
|
||||
if (temp == 0 || temp->pipe == 0)
|
||||
if (temp == 0)
|
||||
return;
|
||||
if (job_index == js.j_current || job_index == js.j_previous)
|
||||
reset_current ();
|
||||
|
||||
proc = find_last_proc (job_index, 0);
|
||||
/* Could do this just for J_ASYNC jobs, but we save all. */
|
||||
if (proc)
|
||||
bgp_add (proc->pid, process_exit_status (proc->status));
|
||||
if ((dflags & DEL_NOBGPID) == 0)
|
||||
{
|
||||
proc = find_last_proc (job_index, 0);
|
||||
/* Could do this just for J_ASYNC jobs, but we save all. */
|
||||
if (proc)
|
||||
bgp_add (proc->pid, process_exit_status (proc->status));
|
||||
}
|
||||
|
||||
jobs[job_index] = (JOB *)NULL;
|
||||
if (temp == js.j_lastmade)
|
||||
@@ -1093,6 +1174,8 @@ map_over_jobs (func, arg1, arg2)
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("map_over_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
if (jobs[i])
|
||||
{
|
||||
@@ -1231,8 +1314,10 @@ find_job (pid, alive_only, procp)
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("find_job: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
if (jobs[i] && jobs[i]->pipe)
|
||||
if (jobs[i])
|
||||
{
|
||||
p = jobs[i]->pipe;
|
||||
|
||||
@@ -1657,7 +1742,7 @@ make_child (command, async_p)
|
||||
In this case, we don't want to give the terminal to the
|
||||
shell's process group (we could be in the middle of a
|
||||
pipeline, for example). */
|
||||
if (async_p == 0 && pipeline_pgrp != shell_pgrp)
|
||||
if (async_p == 0 && pipeline_pgrp != shell_pgrp && ((subshell_environment&SUBSHELL_ASYNC) == 0))
|
||||
give_terminal_to (pipeline_pgrp, 0);
|
||||
|
||||
#if defined (PGRP_PIPE)
|
||||
@@ -1699,6 +1784,13 @@ make_child (command, async_p)
|
||||
/* In the parent. Remember the pid of the child just created
|
||||
as the proper pgrp if this is the first child. */
|
||||
|
||||
if (first_pid == NO_PID)
|
||||
first_pid = pid;
|
||||
else if (pid_wrap == -1 && pid < first_pid)
|
||||
pid_wrap = 0;
|
||||
else if (pid_wrap == 0 && pid >= first_pid)
|
||||
pid_wrap = 1;
|
||||
|
||||
if (job_control)
|
||||
{
|
||||
if (pipeline_pgrp == 0)
|
||||
@@ -1732,6 +1824,9 @@ make_child (command, async_p)
|
||||
last_asynchronous_pid = 1;
|
||||
#endif
|
||||
|
||||
if (pid_wrap > 0)
|
||||
delete_old_job (pid);
|
||||
|
||||
#if !defined (RECYCLES_PIDS)
|
||||
/* Only check for saved status if we've saved more than CHILD_MAX
|
||||
statuses, unless the system recycles pids. */
|
||||
@@ -2000,12 +2095,14 @@ wait_for_background_pids ()
|
||||
BLOCK_CHILD (set, oset);
|
||||
|
||||
/* find first running job; if none running in foreground, break */
|
||||
/* XXX could use js.j_firstj here */
|
||||
/* XXX could use js.j_firstj and js.j_lastj here */
|
||||
for (i = 0; i < js.j_jobslots; i++)
|
||||
{
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("wait_for_background_pids: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("wait_for_background_pids: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0)
|
||||
break;
|
||||
@@ -2200,7 +2297,11 @@ wait_for (pid)
|
||||
/* This is possibly a race condition -- should it go in stop_pipeline? */
|
||||
wait_sigint_received = 0;
|
||||
if (job_control == 0)
|
||||
old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler);
|
||||
{
|
||||
old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler);
|
||||
if (old_sigint_handler == SIG_IGN)
|
||||
set_signal_handler (SIGINT, old_sigint_handler);
|
||||
}
|
||||
|
||||
termination_state = last_command_exit_value;
|
||||
|
||||
@@ -2267,6 +2368,7 @@ wait_for (pid)
|
||||
{
|
||||
child->running = PS_DONE;
|
||||
child->status = 0; /* XXX -- can't find true status */
|
||||
js.c_living = 0; /* no living child processes */
|
||||
if (job != NO_JOB)
|
||||
{
|
||||
jobs[job]->state = JDEAD;
|
||||
@@ -2318,7 +2420,6 @@ wait_for (pid)
|
||||
if (job == NO_JOB)
|
||||
itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)", (long)shell_pgrp);
|
||||
#endif
|
||||
|
||||
give_terminal_to (shell_pgrp, 0);
|
||||
}
|
||||
|
||||
@@ -2899,7 +3000,10 @@ waitchld (wpid, block)
|
||||
/* 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)
|
||||
children_exited++;
|
||||
{
|
||||
children_exited++;
|
||||
js.c_living--;
|
||||
}
|
||||
|
||||
/* Locate our PROCESS for this pid. */
|
||||
child = find_process (pid, 1, &job); /* want living procs only */
|
||||
@@ -3600,7 +3704,7 @@ give_terminal_to (pgrp, force)
|
||||
if (tcsetpgrp (shell_tty, pgrp) < 0)
|
||||
{
|
||||
/* Maybe we should print an error message? */
|
||||
#if 0
|
||||
#ifdef DEBUG
|
||||
sys_error ("tcsetpgrp(%d) failed: pid %ld to pgrp %ld",
|
||||
shell_tty, (long)getpid(), (long)pgrp);
|
||||
#endif
|
||||
@@ -3639,9 +3743,11 @@ delete_all_jobs (running_only)
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("delete_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i))))
|
||||
delete_job (i, 1);
|
||||
delete_job (i, DEL_WARNSTOPPED);
|
||||
}
|
||||
if (running_only == 0)
|
||||
{
|
||||
@@ -3693,6 +3799,8 @@ count_all_jobs ()
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("count_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
if (jobs[i] && DEADJOB(i) == 0)
|
||||
n++;
|
||||
@@ -3766,6 +3874,8 @@ mark_dead_jobs_as_notified (force)
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
if (jobs[i] && DEADJOB (i))
|
||||
{
|
||||
@@ -3817,6 +3927,8 @@ itrace("mark_dead_jobs_as_notified: child_max = %d ndead = %d ndeadproc = %d", j
|
||||
#if defined (DEBUG)
|
||||
if (i < js.j_firstj && jobs[i])
|
||||
itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
|
||||
if (i > js.j_lastj && jobs[i])
|
||||
itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
|
||||
#endif
|
||||
/* If marking this job as notified would drop us down below
|
||||
child_max, don't mark it so we can keep at least child_max
|
||||
|
||||
@@ -1033,8 +1033,10 @@ pending input has not already been read with @code{rl_read_key()}.
|
||||
@deftypefun int rl_set_keyboard_input_timeout (int u)
|
||||
While waiting for keyboard input in @code{rl_read_key()}, Readline will
|
||||
wait for @var{u} microseconds for input before calling any function
|
||||
assigned to @code{rl_event_hook}. The default waiting period is
|
||||
one-tenth of a second. Returns the old timeout value.
|
||||
assigned to @code{rl_event_hook}. @var{u} must be greater than or equal
|
||||
to zero (a zero-length timeout is equivalent to a poll).
|
||||
The default waiting period is one-tenth of a second.
|
||||
Returns the old timeout value.
|
||||
@end deftypefun
|
||||
|
||||
@node Terminal Management
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,10 @@
|
||||
@ignore
|
||||
Copyright (C) 1988-2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-2006 Free Software Foundation, Inc.
|
||||
@end ignore
|
||||
|
||||
@set EDITION 5.1
|
||||
@set VERSION 5.1
|
||||
@set UPDATED 11 November 2005
|
||||
@set UPDATED-MONTH November 2005
|
||||
@set UPDATED 14 January 2006
|
||||
@set UPDATED-MONTH January 2006
|
||||
|
||||
@set LASTCHANGE Fri Nov 11 19:50:51 EST 2005
|
||||
@set LASTCHANGE Sat Jan 14 21:10:59 EST 2006
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
Copyright (C) 1988-2005 Free Software Foundation, Inc.
|
||||
@end ignore
|
||||
|
||||
@set EDITION 5.1-beta1
|
||||
@set VERSION 5.1-beta1
|
||||
@set EDITION 5.1
|
||||
@set VERSION 5.1
|
||||
@set UPDATED 11 November 2005
|
||||
@set UPDATED-MONTH November 2005
|
||||
|
||||
|
||||
@@ -263,7 +263,7 @@ rl_set_keyboard_input_timeout (u)
|
||||
int o;
|
||||
|
||||
o = _keyboard_input_timeout;
|
||||
if (u > 0)
|
||||
if (u >= 0)
|
||||
_keyboard_input_timeout = u;
|
||||
return (o);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,570 @@
|
||||
/* input.c -- character input functions for readline. */
|
||||
|
||||
/* Copyright (C) 1994-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Readline Library, a library for
|
||||
reading lines of text with interactive input and history editing.
|
||||
|
||||
The GNU Readline Library is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2, or
|
||||
(at your option) any later version.
|
||||
|
||||
The GNU Readline Library 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.
|
||||
|
||||
The GNU General Public License is often shipped with GNU software, and
|
||||
is generally kept in a file called COPYING or LICENSE. If you do not
|
||||
have a copy of the license, write to the Free Software Foundation,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
#define READLINE_LIBRARY
|
||||
|
||||
#if defined (__TANDEM)
|
||||
# include <floss.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#if defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif /* HAVE_SYS_FILE_H */
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
#if defined (HAVE_STDLIB_H)
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# include "ansi_stdlib.h"
|
||||
#endif /* HAVE_STDLIB_H */
|
||||
|
||||
#if defined (HAVE_SELECT)
|
||||
# if !defined (HAVE_SYS_SELECT_H) || !defined (M_UNIX)
|
||||
# include <sys/time.h>
|
||||
# endif
|
||||
#endif /* HAVE_SELECT */
|
||||
#if defined (HAVE_SYS_SELECT_H)
|
||||
# include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#if defined (FIONREAD_IN_SYS_IOCTL)
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
/* System-specific feature definitions and include files. */
|
||||
#include "rldefs.h"
|
||||
#include "rlmbutil.h"
|
||||
|
||||
/* Some standard library routines. */
|
||||
#include "readline.h"
|
||||
|
||||
#include "rlprivate.h"
|
||||
#include "rlshell.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* What kind of non-blocking I/O do we have? */
|
||||
#if !defined (O_NDELAY) && defined (O_NONBLOCK)
|
||||
# define O_NDELAY O_NONBLOCK /* Posix style */
|
||||
#endif
|
||||
|
||||
/* Non-null means it is a pointer to a function to run while waiting for
|
||||
character input. */
|
||||
rl_hook_func_t *rl_event_hook = (rl_hook_func_t *)NULL;
|
||||
|
||||
rl_getc_func_t *rl_getc_function = rl_getc;
|
||||
|
||||
static int _keyboard_input_timeout = 100000; /* 0.1 seconds; it's in usec */
|
||||
|
||||
static int ibuffer_space PARAMS((void));
|
||||
static int rl_get_char PARAMS((int *));
|
||||
static int rl_gather_tyi PARAMS((void));
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Character Input Buffering */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
static int pop_index, push_index;
|
||||
static unsigned char ibuffer[512];
|
||||
static int ibuffer_len = sizeof (ibuffer) - 1;
|
||||
|
||||
#define any_typein (push_index != pop_index)
|
||||
|
||||
int
|
||||
_rl_any_typein ()
|
||||
{
|
||||
return any_typein;
|
||||
}
|
||||
|
||||
/* Return the amount of space available in the buffer for stuffing
|
||||
characters. */
|
||||
static int
|
||||
ibuffer_space ()
|
||||
{
|
||||
if (pop_index > push_index)
|
||||
return (pop_index - push_index - 1);
|
||||
else
|
||||
return (ibuffer_len - (push_index - pop_index));
|
||||
}
|
||||
|
||||
/* Get a key from the buffer of characters to be read.
|
||||
Return the key in KEY.
|
||||
Result is KEY if there was a key, or 0 if there wasn't. */
|
||||
static int
|
||||
rl_get_char (key)
|
||||
int *key;
|
||||
{
|
||||
if (push_index == pop_index)
|
||||
return (0);
|
||||
|
||||
*key = ibuffer[pop_index++];
|
||||
|
||||
if (pop_index >= ibuffer_len)
|
||||
pop_index = 0;
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Stuff KEY into the *front* of the input buffer.
|
||||
Returns non-zero if successful, zero if there is
|
||||
no space left in the buffer. */
|
||||
int
|
||||
_rl_unget_char (key)
|
||||
int key;
|
||||
{
|
||||
if (ibuffer_space ())
|
||||
{
|
||||
pop_index--;
|
||||
if (pop_index < 0)
|
||||
pop_index = ibuffer_len - 1;
|
||||
ibuffer[pop_index] = key;
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
_rl_pushed_input_available ()
|
||||
{
|
||||
return (push_index != pop_index);
|
||||
}
|
||||
|
||||
/* If a character is available to be read, then read it and stuff it into
|
||||
IBUFFER. Otherwise, just return. Returns number of characters read
|
||||
(0 if none available) and -1 on error (EIO). */
|
||||
static int
|
||||
rl_gather_tyi ()
|
||||
{
|
||||
int tty;
|
||||
register int tem, result;
|
||||
int chars_avail, k;
|
||||
char input;
|
||||
#if defined(HAVE_SELECT)
|
||||
fd_set readfds, exceptfds;
|
||||
struct timeval timeout;
|
||||
#endif
|
||||
|
||||
tty = fileno (rl_instream);
|
||||
|
||||
#if defined (HAVE_SELECT)
|
||||
FD_ZERO (&readfds);
|
||||
FD_ZERO (&exceptfds);
|
||||
FD_SET (tty, &readfds);
|
||||
FD_SET (tty, &exceptfds);
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = _keyboard_input_timeout;
|
||||
result = select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout);
|
||||
if (result <= 0)
|
||||
return 0; /* Nothing to read. */
|
||||
#endif
|
||||
|
||||
result = -1;
|
||||
#if defined (FIONREAD)
|
||||
errno = 0;
|
||||
result = ioctl (tty, FIONREAD, &chars_avail);
|
||||
if (result == -1 && errno == EIO)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
#if defined (O_NDELAY)
|
||||
if (result == -1)
|
||||
{
|
||||
tem = fcntl (tty, F_GETFL, 0);
|
||||
|
||||
fcntl (tty, F_SETFL, (tem | O_NDELAY));
|
||||
chars_avail = read (tty, &input, 1);
|
||||
|
||||
fcntl (tty, F_SETFL, tem);
|
||||
if (chars_avail == -1 && errno == EAGAIN)
|
||||
return 0;
|
||||
if (chars_avail == 0) /* EOF */
|
||||
{
|
||||
rl_stuff_char (EOF);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
#endif /* O_NDELAY */
|
||||
|
||||
/* If there's nothing available, don't waste time trying to read
|
||||
something. */
|
||||
if (chars_avail <= 0)
|
||||
return 0;
|
||||
|
||||
tem = ibuffer_space ();
|
||||
|
||||
if (chars_avail > tem)
|
||||
chars_avail = tem;
|
||||
|
||||
/* One cannot read all of the available input. I can only read a single
|
||||
character at a time, or else programs which require input can be
|
||||
thwarted. If the buffer is larger than one character, I lose.
|
||||
Damn! */
|
||||
if (tem < ibuffer_len)
|
||||
chars_avail = 0;
|
||||
|
||||
if (result != -1)
|
||||
{
|
||||
while (chars_avail--)
|
||||
{
|
||||
k = (*rl_getc_function) (rl_instream);
|
||||
rl_stuff_char (k);
|
||||
if (k == NEWLINE || k == RETURN)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chars_avail)
|
||||
rl_stuff_char (input);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
rl_set_keyboard_input_timeout (u)
|
||||
int u;
|
||||
{
|
||||
int o;
|
||||
|
||||
o = _keyboard_input_timeout;
|
||||
if (u > 0)
|
||||
_keyboard_input_timeout = u;
|
||||
return (o);
|
||||
}
|
||||
|
||||
/* Is there input available to be read on the readline input file
|
||||
descriptor? Only works if the system has select(2) or FIONREAD.
|
||||
Uses the value of _keyboard_input_timeout as the timeout; if another
|
||||
readline function wants to specify a timeout and not leave it up to
|
||||
the user, it should use _rl_input_queued(timeout_value_in_microseconds)
|
||||
instead. */
|
||||
int
|
||||
_rl_input_available ()
|
||||
{
|
||||
#if defined(HAVE_SELECT)
|
||||
fd_set readfds, exceptfds;
|
||||
struct timeval timeout;
|
||||
#endif
|
||||
#if !defined (HAVE_SELECT) && defined(FIONREAD)
|
||||
int chars_avail;
|
||||
#endif
|
||||
int tty;
|
||||
|
||||
tty = fileno (rl_instream);
|
||||
|
||||
#if defined (HAVE_SELECT)
|
||||
FD_ZERO (&readfds);
|
||||
FD_ZERO (&exceptfds);
|
||||
FD_SET (tty, &readfds);
|
||||
FD_SET (tty, &exceptfds);
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = _keyboard_input_timeout;
|
||||
return (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) > 0);
|
||||
#else
|
||||
|
||||
#if defined (FIONREAD)
|
||||
if (ioctl (tty, FIONREAD, &chars_avail) == 0)
|
||||
return (chars_avail);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_rl_input_queued (t)
|
||||
int t;
|
||||
{
|
||||
int old_timeout, r;
|
||||
|
||||
old_timeout = rl_set_keyboard_input_timeout (t);
|
||||
r = _rl_input_available ();
|
||||
rl_set_keyboard_input_timeout (old_timeout);
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
_rl_insert_typein (c)
|
||||
int c;
|
||||
{
|
||||
int key, t, i;
|
||||
char *string;
|
||||
|
||||
i = key = 0;
|
||||
string = (char *)xmalloc (ibuffer_len + 1);
|
||||
string[i++] = (char) c;
|
||||
|
||||
while ((t = rl_get_char (&key)) &&
|
||||
_rl_keymap[key].type == ISFUNC &&
|
||||
_rl_keymap[key].function == rl_insert)
|
||||
string[i++] = key;
|
||||
|
||||
if (t)
|
||||
_rl_unget_char (key);
|
||||
|
||||
string[i] = '\0';
|
||||
rl_insert_text (string);
|
||||
free (string);
|
||||
}
|
||||
|
||||
/* Add KEY to the buffer of characters to be read. Returns 1 if the
|
||||
character was stuffed correctly; 0 otherwise. */
|
||||
int
|
||||
rl_stuff_char (key)
|
||||
int key;
|
||||
{
|
||||
if (ibuffer_space () == 0)
|
||||
return 0;
|
||||
|
||||
if (key == EOF)
|
||||
{
|
||||
key = NEWLINE;
|
||||
rl_pending_input = EOF;
|
||||
RL_SETSTATE (RL_STATE_INPUTPENDING);
|
||||
}
|
||||
ibuffer[push_index++] = key;
|
||||
if (push_index >= ibuffer_len)
|
||||
push_index = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Make C be the next command to be executed. */
|
||||
int
|
||||
rl_execute_next (c)
|
||||
int c;
|
||||
{
|
||||
rl_pending_input = c;
|
||||
RL_SETSTATE (RL_STATE_INPUTPENDING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Clear any pending input pushed with rl_execute_next() */
|
||||
int
|
||||
rl_clear_pending_input ()
|
||||
{
|
||||
rl_pending_input = 0;
|
||||
RL_UNSETSTATE (RL_STATE_INPUTPENDING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Character Input */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Read a key, including pending input. */
|
||||
int
|
||||
rl_read_key ()
|
||||
{
|
||||
int c;
|
||||
|
||||
rl_key_sequence_length++;
|
||||
|
||||
if (rl_pending_input)
|
||||
{
|
||||
c = rl_pending_input;
|
||||
rl_clear_pending_input ();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If input is coming from a macro, then use that. */
|
||||
if (c = _rl_next_macro_key ())
|
||||
return (c);
|
||||
|
||||
/* If the user has an event function, then call it periodically. */
|
||||
if (rl_event_hook)
|
||||
{
|
||||
while (rl_event_hook && rl_get_char (&c) == 0)
|
||||
{
|
||||
(*rl_event_hook) ();
|
||||
if (rl_done) /* XXX - experimental */
|
||||
return ('\n');
|
||||
if (rl_gather_tyi () < 0) /* XXX - EIO */
|
||||
{
|
||||
rl_done = 1;
|
||||
return ('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rl_get_char (&c) == 0)
|
||||
c = (*rl_getc_function) (rl_instream);
|
||||
}
|
||||
}
|
||||
|
||||
return (c);
|
||||
}
|
||||
|
||||
int
|
||||
rl_getc (stream)
|
||||
FILE *stream;
|
||||
{
|
||||
int result;
|
||||
unsigned char c;
|
||||
|
||||
while (1)
|
||||
{
|
||||
#if defined (__MINGW32__)
|
||||
if (isatty (fileno (stream)))
|
||||
return (getch ());
|
||||
#endif
|
||||
result = read (fileno (stream), &c, sizeof (unsigned char));
|
||||
|
||||
if (result == sizeof (unsigned char))
|
||||
return (c);
|
||||
|
||||
/* If zero characters are returned, then the file that we are
|
||||
reading from is empty! Return EOF in that case. */
|
||||
if (result == 0)
|
||||
return (EOF);
|
||||
|
||||
#if defined (__BEOS__)
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
#if defined (EWOULDBLOCK)
|
||||
# define X_EWOULDBLOCK EWOULDBLOCK
|
||||
#else
|
||||
# define X_EWOULDBLOCK -99
|
||||
#endif
|
||||
|
||||
#if defined (EAGAIN)
|
||||
# define X_EAGAIN EAGAIN
|
||||
#else
|
||||
# define X_EAGAIN -99
|
||||
#endif
|
||||
|
||||
if (errno == X_EWOULDBLOCK || errno == X_EAGAIN)
|
||||
{
|
||||
if (sh_unset_nodelay_mode (fileno (stream)) < 0)
|
||||
return (EOF);
|
||||
continue;
|
||||
}
|
||||
|
||||
#undef X_EWOULDBLOCK
|
||||
#undef X_EAGAIN
|
||||
|
||||
/* If the error that we received was SIGINT, then try again,
|
||||
this is simply an interrupted system call to read ().
|
||||
Otherwise, some error ocurred, also signifying EOF. */
|
||||
if (errno != EINTR)
|
||||
return (EOF);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
/* read multibyte char */
|
||||
int
|
||||
_rl_read_mbchar (mbchar, size)
|
||||
char *mbchar;
|
||||
int size;
|
||||
{
|
||||
int mb_len = 0;
|
||||
size_t mbchar_bytes_length;
|
||||
wchar_t wc;
|
||||
mbstate_t ps, ps_back;
|
||||
|
||||
memset(&ps, 0, sizeof (mbstate_t));
|
||||
memset(&ps_back, 0, sizeof (mbstate_t));
|
||||
|
||||
while (mb_len < size)
|
||||
{
|
||||
RL_SETSTATE(RL_STATE_MOREINPUT);
|
||||
mbchar[mb_len++] = rl_read_key ();
|
||||
RL_UNSETSTATE(RL_STATE_MOREINPUT);
|
||||
|
||||
mbchar_bytes_length = mbrtowc (&wc, mbchar, mb_len, &ps);
|
||||
if (mbchar_bytes_length == (size_t)(-1))
|
||||
break; /* invalid byte sequence for the current locale */
|
||||
else if (mbchar_bytes_length == (size_t)(-2))
|
||||
{
|
||||
/* shorted bytes */
|
||||
ps = ps_back;
|
||||
continue;
|
||||
}
|
||||
else if (mbchar_bytes_length == 0)
|
||||
{
|
||||
mbchar[0] = '\0'; /* null wide character */
|
||||
mb_len = 1;
|
||||
break;
|
||||
}
|
||||
else if (mbchar_bytes_length > (size_t)(0))
|
||||
break;
|
||||
}
|
||||
|
||||
return mb_len;
|
||||
}
|
||||
|
||||
/* Read a multibyte-character string whose first character is FIRST into
|
||||
the buffer MB of length MBLEN. Returns the last character read, which
|
||||
may be FIRST. Used by the search functions, among others. Very similar
|
||||
to _rl_read_mbchar. */
|
||||
int
|
||||
_rl_read_mbstring (first, mb, mblen)
|
||||
int first;
|
||||
char *mb;
|
||||
int mblen;
|
||||
{
|
||||
int i, c;
|
||||
mbstate_t ps;
|
||||
|
||||
c = first;
|
||||
memset (mb, 0, mblen);
|
||||
for (i = 0; i < mblen; i++)
|
||||
{
|
||||
mb[i] = (char)c;
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
if (_rl_get_char_len (mb, &ps) == -2)
|
||||
{
|
||||
/* Read more for multibyte character */
|
||||
RL_SETSTATE (RL_STATE_MOREINPUT);
|
||||
c = rl_read_key ();
|
||||
RL_UNSETSTATE (RL_STATE_MOREINPUT);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
@@ -122,7 +122,7 @@ char *_rl_term_up;
|
||||
static char *_rl_visible_bell;
|
||||
|
||||
/* Non-zero means the terminal can auto-wrap lines. */
|
||||
int _rl_term_autowrap;
|
||||
int _rl_term_autowrap = -1;
|
||||
|
||||
/* Non-zero means that this terminal has a meta key. */
|
||||
static int term_has_meta;
|
||||
@@ -274,6 +274,9 @@ void
|
||||
_rl_set_screen_size (rows, cols)
|
||||
int rows, cols;
|
||||
{
|
||||
if (_rl_term_autowrap == -1)
|
||||
_rl_init_terminal_io (rl_terminal_name);
|
||||
|
||||
if (rows > 0)
|
||||
_rl_screenheight = rows;
|
||||
if (cols > 0)
|
||||
|
||||
@@ -0,0 +1,701 @@
|
||||
/* terminal.c -- controlling the terminal with termcap. */
|
||||
|
||||
/* Copyright (C) 1996-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Readline Library, a library for
|
||||
reading lines of text with interactive input and history editing.
|
||||
|
||||
The GNU Readline Library is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2, or
|
||||
(at your option) any later version.
|
||||
|
||||
The GNU Readline Library 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.
|
||||
|
||||
The GNU General Public License is often shipped with GNU software, and
|
||||
is generally kept in a file called COPYING or LICENSE. If you do not
|
||||
have a copy of the license, write to the Free Software Foundation,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
#define READLINE_LIBRARY
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "posixstat.h"
|
||||
#include <fcntl.h>
|
||||
#if defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif /* HAVE_SYS_FILE_H */
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
#if defined (HAVE_STDLIB_H)
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# include "ansi_stdlib.h"
|
||||
#endif /* HAVE_STDLIB_H */
|
||||
|
||||
#if defined (HAVE_LOCALE_H)
|
||||
# include <locale.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* System-specific feature definitions and include files. */
|
||||
#include "rldefs.h"
|
||||
|
||||
#if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ)
|
||||
# include <sys/ioctl.h>
|
||||
#endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */
|
||||
|
||||
#include "rltty.h"
|
||||
#include "tcap.h"
|
||||
|
||||
/* Some standard library routines. */
|
||||
#include "readline.h"
|
||||
#include "history.h"
|
||||
|
||||
#include "rlprivate.h"
|
||||
#include "rlshell.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#define CUSTOM_REDISPLAY_FUNC() (rl_redisplay_function != rl_redisplay)
|
||||
#define CUSTOM_INPUT_FUNC() (rl_getc_function != rl_getc)
|
||||
|
||||
int rl_prefer_env_winsize;
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Terminal and Termcap */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
static char *term_buffer = (char *)NULL;
|
||||
static char *term_string_buffer = (char *)NULL;
|
||||
|
||||
static int tcap_initialized;
|
||||
|
||||
#if !defined (__linux__)
|
||||
# if defined (__EMX__) || defined (NEED_EXTERN_PC)
|
||||
extern
|
||||
# endif /* __EMX__ || NEED_EXTERN_PC */
|
||||
char PC, *BC, *UP;
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* Some strings to control terminal actions. These are output by tputs (). */
|
||||
char *_rl_term_clreol;
|
||||
char *_rl_term_clrpag;
|
||||
char *_rl_term_cr;
|
||||
char *_rl_term_backspace;
|
||||
char *_rl_term_goto;
|
||||
char *_rl_term_pc;
|
||||
|
||||
/* Non-zero if we determine that the terminal can do character insertion. */
|
||||
int _rl_terminal_can_insert = 0;
|
||||
|
||||
/* How to insert characters. */
|
||||
char *_rl_term_im;
|
||||
char *_rl_term_ei;
|
||||
char *_rl_term_ic;
|
||||
char *_rl_term_ip;
|
||||
char *_rl_term_IC;
|
||||
|
||||
/* How to delete characters. */
|
||||
char *_rl_term_dc;
|
||||
char *_rl_term_DC;
|
||||
|
||||
#if defined (HACK_TERMCAP_MOTION)
|
||||
char *_rl_term_forward_char;
|
||||
#endif /* HACK_TERMCAP_MOTION */
|
||||
|
||||
/* How to go up a line. */
|
||||
char *_rl_term_up;
|
||||
|
||||
/* A visible bell; char if the terminal can be made to flash the screen. */
|
||||
static char *_rl_visible_bell;
|
||||
|
||||
/* Non-zero means the terminal can auto-wrap lines. */
|
||||
int _rl_term_autowrap;
|
||||
|
||||
/* Non-zero means that this terminal has a meta key. */
|
||||
static int term_has_meta;
|
||||
|
||||
/* The sequences to write to turn on and off the meta key, if this
|
||||
terminal has one. */
|
||||
static char *_rl_term_mm;
|
||||
static char *_rl_term_mo;
|
||||
|
||||
/* The key sequences output by the arrow keys, if this terminal has any. */
|
||||
static char *_rl_term_ku;
|
||||
static char *_rl_term_kd;
|
||||
static char *_rl_term_kr;
|
||||
static char *_rl_term_kl;
|
||||
|
||||
/* How to initialize and reset the arrow keys, if this terminal has any. */
|
||||
static char *_rl_term_ks;
|
||||
static char *_rl_term_ke;
|
||||
|
||||
/* The key sequences sent by the Home and End keys, if any. */
|
||||
static char *_rl_term_kh;
|
||||
static char *_rl_term_kH;
|
||||
static char *_rl_term_at7; /* @7 */
|
||||
|
||||
/* Delete key */
|
||||
static char *_rl_term_kD;
|
||||
|
||||
/* Insert key */
|
||||
static char *_rl_term_kI;
|
||||
|
||||
/* Cursor control */
|
||||
static char *_rl_term_vs; /* very visible */
|
||||
static char *_rl_term_ve; /* normal */
|
||||
|
||||
static void bind_termcap_arrow_keys PARAMS((Keymap));
|
||||
|
||||
/* Variables that hold the screen dimensions, used by the display code. */
|
||||
int _rl_screenwidth, _rl_screenheight, _rl_screenchars;
|
||||
|
||||
/* Non-zero means the user wants to enable the keypad. */
|
||||
int _rl_enable_keypad;
|
||||
|
||||
/* Non-zero means the user wants to enable a meta key. */
|
||||
int _rl_enable_meta = 1;
|
||||
|
||||
#if defined (__EMX__)
|
||||
static void
|
||||
_emx_get_screensize (swp, shp)
|
||||
int *swp, *shp;
|
||||
{
|
||||
int sz[2];
|
||||
|
||||
_scrsize (sz);
|
||||
|
||||
if (swp)
|
||||
*swp = sz[0];
|
||||
if (shp)
|
||||
*shp = sz[1];
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get readline's idea of the screen size. TTY is a file descriptor open
|
||||
to the terminal. If IGNORE_ENV is true, we do not pay attention to the
|
||||
values of $LINES and $COLUMNS. The tests for TERM_STRING_BUFFER being
|
||||
non-null serve to check whether or not we have initialized termcap. */
|
||||
void
|
||||
_rl_get_screen_size (tty, ignore_env)
|
||||
int tty, ignore_env;
|
||||
{
|
||||
char *ss;
|
||||
#if defined (TIOCGWINSZ)
|
||||
struct winsize window_size;
|
||||
#endif /* TIOCGWINSZ */
|
||||
int wr, wc;
|
||||
|
||||
wr = wc = -1;
|
||||
#if defined (TIOCGWINSZ)
|
||||
if (ioctl (tty, TIOCGWINSZ, &window_size) == 0)
|
||||
{
|
||||
wc = (int) window_size.ws_col;
|
||||
wr = (int) window_size.ws_row;
|
||||
}
|
||||
#endif /* TIOCGWINSZ */
|
||||
|
||||
#if defined (__EMX__)
|
||||
_emx_get_screensize (&_rl_screenwidth, &_rl_screenheight);
|
||||
#endif
|
||||
|
||||
if (ignore_env || rl_prefer_env_winsize == 0)
|
||||
{
|
||||
_rl_screenwidth = wc;
|
||||
_rl_screenheight = wr;
|
||||
}
|
||||
else
|
||||
_rl_screenwidth = _rl_screenheight = -1;
|
||||
|
||||
/* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV
|
||||
is unset. If we prefer the environment, check it first before
|
||||
assigning the value returned by the kernel. */
|
||||
if (_rl_screenwidth <= 0)
|
||||
{
|
||||
if (ignore_env == 0 && (ss = sh_get_env_value ("COLUMNS")))
|
||||
_rl_screenwidth = atoi (ss);
|
||||
|
||||
if (_rl_screenwidth <= 0)
|
||||
_rl_screenwidth = wc;
|
||||
|
||||
#if !defined (__DJGPP__)
|
||||
if (_rl_screenwidth <= 0 && term_string_buffer)
|
||||
_rl_screenwidth = tgetnum ("co");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Environment variable LINES overrides setting of "li" if IGNORE_ENV
|
||||
is unset. */
|
||||
if (_rl_screenheight <= 0)
|
||||
{
|
||||
if (ignore_env == 0 && (ss = sh_get_env_value ("LINES")))
|
||||
_rl_screenheight = atoi (ss);
|
||||
|
||||
if (_rl_screenheight <= 0)
|
||||
_rl_screenheight = wr;
|
||||
|
||||
#if !defined (__DJGPP__)
|
||||
if (_rl_screenheight <= 0 && term_string_buffer)
|
||||
_rl_screenheight = tgetnum ("li");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* If all else fails, default to 80x24 terminal. */
|
||||
if (_rl_screenwidth <= 1)
|
||||
_rl_screenwidth = 80;
|
||||
|
||||
if (_rl_screenheight <= 0)
|
||||
_rl_screenheight = 24;
|
||||
|
||||
/* If we're being compiled as part of bash, set the environment
|
||||
variables $LINES and $COLUMNS to new values. Otherwise, just
|
||||
do a pair of putenv () or setenv () calls. */
|
||||
sh_set_lines_and_columns (_rl_screenheight, _rl_screenwidth);
|
||||
|
||||
if (_rl_term_autowrap == 0)
|
||||
_rl_screenwidth--;
|
||||
|
||||
_rl_screenchars = _rl_screenwidth * _rl_screenheight;
|
||||
}
|
||||
|
||||
void
|
||||
_rl_set_screen_size (rows, cols)
|
||||
int rows, cols;
|
||||
{
|
||||
if (RL_ISSTATE(RL_STATE_INITIALIZED) == 0)
|
||||
_rl_init_terminal_io (rl_terminal_name);
|
||||
|
||||
if (rows > 0)
|
||||
_rl_screenheight = rows;
|
||||
if (cols > 0)
|
||||
{
|
||||
_rl_screenwidth = cols;
|
||||
if (_rl_term_autowrap == 0)
|
||||
_rl_screenwidth--;
|
||||
}
|
||||
|
||||
if (rows > 0 || cols > 0)
|
||||
_rl_screenchars = _rl_screenwidth * _rl_screenheight;
|
||||
}
|
||||
|
||||
void
|
||||
rl_set_screen_size (rows, cols)
|
||||
int rows, cols;
|
||||
{
|
||||
_rl_set_screen_size (rows, cols);
|
||||
}
|
||||
|
||||
void
|
||||
rl_get_screen_size (rows, cols)
|
||||
int *rows, *cols;
|
||||
{
|
||||
if (rows)
|
||||
*rows = _rl_screenheight;
|
||||
if (cols)
|
||||
*cols = _rl_screenwidth;
|
||||
}
|
||||
|
||||
void
|
||||
rl_reset_screen_size ()
|
||||
{
|
||||
_rl_get_screen_size (fileno (rl_instream), 0);
|
||||
}
|
||||
|
||||
void
|
||||
rl_resize_terminal ()
|
||||
{
|
||||
if (readline_echoing_p)
|
||||
{
|
||||
_rl_get_screen_size (fileno (rl_instream), 1);
|
||||
if (CUSTOM_REDISPLAY_FUNC ())
|
||||
rl_forced_update_display ();
|
||||
else
|
||||
_rl_redisplay_after_sigwinch ();
|
||||
}
|
||||
}
|
||||
|
||||
struct _tc_string {
|
||||
const char *tc_var;
|
||||
char **tc_value;
|
||||
};
|
||||
|
||||
/* This should be kept sorted, just in case we decide to change the
|
||||
search algorithm to something smarter. */
|
||||
static struct _tc_string tc_strings[] =
|
||||
{
|
||||
{ "@7", &_rl_term_at7 },
|
||||
{ "DC", &_rl_term_DC },
|
||||
{ "IC", &_rl_term_IC },
|
||||
{ "ce", &_rl_term_clreol },
|
||||
{ "cl", &_rl_term_clrpag },
|
||||
{ "cr", &_rl_term_cr },
|
||||
{ "dc", &_rl_term_dc },
|
||||
{ "ei", &_rl_term_ei },
|
||||
{ "ic", &_rl_term_ic },
|
||||
{ "im", &_rl_term_im },
|
||||
{ "kD", &_rl_term_kD }, /* delete */
|
||||
{ "kH", &_rl_term_kH }, /* home down ?? */
|
||||
{ "kI", &_rl_term_kI }, /* insert */
|
||||
{ "kd", &_rl_term_kd },
|
||||
{ "ke", &_rl_term_ke }, /* end keypad mode */
|
||||
{ "kh", &_rl_term_kh }, /* home */
|
||||
{ "kl", &_rl_term_kl },
|
||||
{ "kr", &_rl_term_kr },
|
||||
{ "ks", &_rl_term_ks }, /* start keypad mode */
|
||||
{ "ku", &_rl_term_ku },
|
||||
{ "le", &_rl_term_backspace },
|
||||
{ "mm", &_rl_term_mm },
|
||||
{ "mo", &_rl_term_mo },
|
||||
#if defined (HACK_TERMCAP_MOTION)
|
||||
{ "nd", &_rl_term_forward_char },
|
||||
#endif
|
||||
{ "pc", &_rl_term_pc },
|
||||
{ "up", &_rl_term_up },
|
||||
{ "vb", &_rl_visible_bell },
|
||||
{ "vs", &_rl_term_vs },
|
||||
{ "ve", &_rl_term_ve },
|
||||
};
|
||||
|
||||
#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
|
||||
|
||||
/* Read the desired terminal capability strings into BP. The capabilities
|
||||
are described in the TC_STRINGS table. */
|
||||
static void
|
||||
get_term_capabilities (bp)
|
||||
char **bp;
|
||||
{
|
||||
#if !defined (__DJGPP__) /* XXX - doesn't DJGPP have a termcap library? */
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < NUM_TC_STRINGS; i++)
|
||||
*(tc_strings[i].tc_value) = tgetstr ((char *)tc_strings[i].tc_var, bp);
|
||||
#endif
|
||||
tcap_initialized = 1;
|
||||
}
|
||||
|
||||
int
|
||||
_rl_init_terminal_io (terminal_name)
|
||||
const char *terminal_name;
|
||||
{
|
||||
const char *term;
|
||||
char *buffer;
|
||||
int tty, tgetent_ret;
|
||||
|
||||
term = terminal_name ? terminal_name : sh_get_env_value ("TERM");
|
||||
_rl_term_clrpag = _rl_term_cr = _rl_term_clreol = (char *)NULL;
|
||||
tty = rl_instream ? fileno (rl_instream) : 0;
|
||||
|
||||
if (term == 0)
|
||||
term = "dumb";
|
||||
|
||||
/* I've separated this out for later work on not calling tgetent at all
|
||||
if the calling application has supplied a custom redisplay function,
|
||||
(and possibly if the application has supplied a custom input function). */
|
||||
if (CUSTOM_REDISPLAY_FUNC())
|
||||
{
|
||||
tgetent_ret = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (term_string_buffer == 0)
|
||||
term_string_buffer = (char *)xmalloc(2032);
|
||||
|
||||
if (term_buffer == 0)
|
||||
term_buffer = (char *)xmalloc(4080);
|
||||
|
||||
buffer = term_string_buffer;
|
||||
|
||||
tgetent_ret = tgetent (term_buffer, term);
|
||||
}
|
||||
|
||||
if (tgetent_ret <= 0)
|
||||
{
|
||||
FREE (term_string_buffer);
|
||||
FREE (term_buffer);
|
||||
buffer = term_buffer = term_string_buffer = (char *)NULL;
|
||||
|
||||
_rl_term_autowrap = 0; /* used by _rl_get_screen_size */
|
||||
|
||||
/* Allow calling application to set default height and width, using
|
||||
rl_set_screen_size */
|
||||
if (_rl_screenwidth <= 0 || _rl_screenheight <= 0)
|
||||
{
|
||||
#if defined (__EMX__)
|
||||
_emx_get_screensize (&_rl_screenwidth, &_rl_screenheight);
|
||||
_rl_screenwidth--;
|
||||
#else /* !__EMX__ */
|
||||
_rl_get_screen_size (tty, 0);
|
||||
#endif /* !__EMX__ */
|
||||
}
|
||||
|
||||
/* Defaults. */
|
||||
if (_rl_screenwidth <= 0 || _rl_screenheight <= 0)
|
||||
{
|
||||
_rl_screenwidth = 79;
|
||||
_rl_screenheight = 24;
|
||||
}
|
||||
|
||||
/* Everything below here is used by the redisplay code (tputs). */
|
||||
_rl_screenchars = _rl_screenwidth * _rl_screenheight;
|
||||
_rl_term_cr = "\r";
|
||||
_rl_term_im = _rl_term_ei = _rl_term_ic = _rl_term_IC = (char *)NULL;
|
||||
_rl_term_up = _rl_term_dc = _rl_term_DC = _rl_visible_bell = (char *)NULL;
|
||||
_rl_term_ku = _rl_term_kd = _rl_term_kl = _rl_term_kr = (char *)NULL;
|
||||
_rl_term_kh = _rl_term_kH = _rl_term_kI = _rl_term_kD = (char *)NULL;
|
||||
_rl_term_ks = _rl_term_ke = _rl_term_at7 = (char *)NULL;
|
||||
_rl_term_mm = _rl_term_mo = (char *)NULL;
|
||||
_rl_term_ve = _rl_term_vs = (char *)NULL;
|
||||
#if defined (HACK_TERMCAP_MOTION)
|
||||
term_forward_char = (char *)NULL;
|
||||
#endif
|
||||
_rl_terminal_can_insert = term_has_meta = 0;
|
||||
|
||||
/* Reasonable defaults for tgoto(). Readline currently only uses
|
||||
tgoto if _rl_term_IC or _rl_term_DC is defined, but just in case we
|
||||
change that later... */
|
||||
PC = '\0';
|
||||
BC = _rl_term_backspace = "\b";
|
||||
UP = _rl_term_up;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
get_term_capabilities (&buffer);
|
||||
|
||||
/* Set up the variables that the termcap library expects the application
|
||||
to provide. */
|
||||
PC = _rl_term_pc ? *_rl_term_pc : 0;
|
||||
BC = _rl_term_backspace;
|
||||
UP = _rl_term_up;
|
||||
|
||||
if (!_rl_term_cr)
|
||||
_rl_term_cr = "\r";
|
||||
|
||||
_rl_term_autowrap = tgetflag ("am") && tgetflag ("xn");
|
||||
|
||||
/* Allow calling application to set default height and width, using
|
||||
rl_set_screen_size */
|
||||
if (_rl_screenwidth <= 0 || _rl_screenheight <= 0)
|
||||
_rl_get_screen_size (tty, 0);
|
||||
|
||||
/* "An application program can assume that the terminal can do
|
||||
character insertion if *any one of* the capabilities `IC',
|
||||
`im', `ic' or `ip' is provided." But we can't do anything if
|
||||
only `ip' is provided, so... */
|
||||
_rl_terminal_can_insert = (_rl_term_IC || _rl_term_im || _rl_term_ic);
|
||||
|
||||
/* Check to see if this terminal has a meta key and clear the capability
|
||||
variables if there is none. */
|
||||
term_has_meta = (tgetflag ("km") || tgetflag ("MT"));
|
||||
if (!term_has_meta)
|
||||
_rl_term_mm = _rl_term_mo = (char *)NULL;
|
||||
|
||||
/* Attempt to find and bind the arrow keys. Do not override already
|
||||
bound keys in an overzealous attempt, however. */
|
||||
|
||||
bind_termcap_arrow_keys (emacs_standard_keymap);
|
||||
|
||||
#if defined (VI_MODE)
|
||||
bind_termcap_arrow_keys (vi_movement_keymap);
|
||||
bind_termcap_arrow_keys (vi_insertion_keymap);
|
||||
#endif /* VI_MODE */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bind the arrow key sequences from the termcap description in MAP. */
|
||||
static void
|
||||
bind_termcap_arrow_keys (map)
|
||||
Keymap map;
|
||||
{
|
||||
Keymap xkeymap;
|
||||
|
||||
xkeymap = _rl_keymap;
|
||||
_rl_keymap = map;
|
||||
|
||||
rl_bind_keyseq_if_unbound (_rl_term_ku, rl_get_previous_history);
|
||||
rl_bind_keyseq_if_unbound (_rl_term_kd, rl_get_next_history);
|
||||
rl_bind_keyseq_if_unbound (_rl_term_kr, rl_forward_char);
|
||||
rl_bind_keyseq_if_unbound (_rl_term_kl, rl_backward_char);
|
||||
|
||||
rl_bind_keyseq_if_unbound (_rl_term_kh, rl_beg_of_line); /* Home */
|
||||
rl_bind_keyseq_if_unbound (_rl_term_at7, rl_end_of_line); /* End */
|
||||
|
||||
rl_bind_keyseq_if_unbound (_rl_term_kD, rl_delete);
|
||||
|
||||
_rl_keymap = xkeymap;
|
||||
}
|
||||
|
||||
char *
|
||||
rl_get_termcap (cap)
|
||||
const char *cap;
|
||||
{
|
||||
register int i;
|
||||
|
||||
if (tcap_initialized == 0)
|
||||
return ((char *)NULL);
|
||||
for (i = 0; i < NUM_TC_STRINGS; i++)
|
||||
{
|
||||
if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0)
|
||||
return *(tc_strings[i].tc_value);
|
||||
}
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
/* Re-initialize the terminal considering that the TERM/TERMCAP variable
|
||||
has changed. */
|
||||
int
|
||||
rl_reset_terminal (terminal_name)
|
||||
const char *terminal_name;
|
||||
{
|
||||
_rl_screenwidth = _rl_screenheight = 0;
|
||||
_rl_init_terminal_io (terminal_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A function for the use of tputs () */
|
||||
#ifdef _MINIX
|
||||
void
|
||||
_rl_output_character_function (c)
|
||||
int c;
|
||||
{
|
||||
putc (c, _rl_out_stream);
|
||||
}
|
||||
#else /* !_MINIX */
|
||||
int
|
||||
_rl_output_character_function (c)
|
||||
int c;
|
||||
{
|
||||
return putc (c, _rl_out_stream);
|
||||
}
|
||||
#endif /* !_MINIX */
|
||||
|
||||
/* Write COUNT characters from STRING to the output stream. */
|
||||
void
|
||||
_rl_output_some_chars (string, count)
|
||||
const char *string;
|
||||
int count;
|
||||
{
|
||||
fwrite (string, 1, count, _rl_out_stream);
|
||||
}
|
||||
|
||||
/* Move the cursor back. */
|
||||
int
|
||||
_rl_backspace (count)
|
||||
int count;
|
||||
{
|
||||
register int i;
|
||||
|
||||
if (_rl_term_backspace)
|
||||
for (i = 0; i < count; i++)
|
||||
tputs (_rl_term_backspace, 1, _rl_output_character_function);
|
||||
else
|
||||
for (i = 0; i < count; i++)
|
||||
putc ('\b', _rl_out_stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Move to the start of the next line. */
|
||||
int
|
||||
rl_crlf ()
|
||||
{
|
||||
#if defined (NEW_TTY_DRIVER)
|
||||
if (_rl_term_cr)
|
||||
tputs (_rl_term_cr, 1, _rl_output_character_function);
|
||||
#endif /* NEW_TTY_DRIVER */
|
||||
putc ('\n', _rl_out_stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ring the terminal bell. */
|
||||
int
|
||||
rl_ding ()
|
||||
{
|
||||
if (readline_echoing_p)
|
||||
{
|
||||
switch (_rl_bell_preference)
|
||||
{
|
||||
case NO_BELL:
|
||||
default:
|
||||
break;
|
||||
case VISIBLE_BELL:
|
||||
if (_rl_visible_bell)
|
||||
{
|
||||
tputs (_rl_visible_bell, 1, _rl_output_character_function);
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case AUDIBLE_BELL:
|
||||
fprintf (stderr, "\007");
|
||||
fflush (stderr);
|
||||
break;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Controlling the Meta Key and Keypad */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
void
|
||||
_rl_enable_meta_key ()
|
||||
{
|
||||
#if !defined (__DJGPP__)
|
||||
if (term_has_meta && _rl_term_mm)
|
||||
tputs (_rl_term_mm, 1, _rl_output_character_function);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
_rl_control_keypad (on)
|
||||
int on;
|
||||
{
|
||||
#if !defined (__DJGPP__)
|
||||
if (on && _rl_term_ks)
|
||||
tputs (_rl_term_ks, 1, _rl_output_character_function);
|
||||
else if (!on && _rl_term_ke)
|
||||
tputs (_rl_term_ke, 1, _rl_output_character_function);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Controlling the Cursor */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Set the cursor appropriately depending on IM, which is one of the
|
||||
insert modes (insert or overwrite). Insert mode gets the normal
|
||||
cursor. Overwrite mode gets a very visible cursor. Only does
|
||||
anything if we have both capabilities. */
|
||||
void
|
||||
_rl_set_cursor (im, force)
|
||||
int im, force;
|
||||
{
|
||||
if (_rl_term_ve && _rl_term_vs)
|
||||
{
|
||||
if (force || im != rl_insert_mode)
|
||||
{
|
||||
if (im == RL_IM_OVERWRITE)
|
||||
tputs (_rl_term_vs, 1, _rl_output_character_function);
|
||||
else
|
||||
tputs (_rl_term_ve, 1, _rl_output_character_function);
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
-7
@@ -109,12 +109,16 @@ static int vi_mark_chars['z' - 'a' + 1];
|
||||
static void _rl_vi_stuff_insert PARAMS((int));
|
||||
static void _rl_vi_save_insert PARAMS((UNDO_LIST *));
|
||||
|
||||
static void _rl_vi_backup PARAMS((void));
|
||||
|
||||
static int _rl_vi_arg_dispatch PARAMS((int));
|
||||
static int rl_digit_loop1 PARAMS((void));
|
||||
|
||||
static int _rl_vi_set_mark PARAMS((void));
|
||||
static int _rl_vi_goto_mark PARAMS((void));
|
||||
|
||||
static void _rl_vi_append_forward PARAMS((int));
|
||||
|
||||
static int _rl_vi_callback_getchar PARAMS((char *, int));
|
||||
|
||||
#if defined (READLINE_CALLBACKS)
|
||||
@@ -205,7 +209,16 @@ rl_vi_redo (count, c)
|
||||
_rl_vi_stuff_insert (count);
|
||||
/* And back up point over the last character inserted. */
|
||||
if (rl_point > 0)
|
||||
rl_point--;
|
||||
_rl_vi_backup ();
|
||||
}
|
||||
/* Ditto for redoing an insert with `a', but move forward a character first
|
||||
like the `a' command does. */
|
||||
else if (_rl_vi_last_command == 'a' && vi_insert_buffer && *vi_insert_buffer)
|
||||
{
|
||||
_rl_vi_append_forward ('a');
|
||||
_rl_vi_stuff_insert (count);
|
||||
if (rl_point > 0)
|
||||
_rl_vi_backup ();
|
||||
}
|
||||
else
|
||||
r = _rl_dispatch (_rl_vi_last_command, _rl_keymap);
|
||||
@@ -575,23 +588,32 @@ rl_vi_insert_beg (count, key)
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
rl_vi_append_mode (count, key)
|
||||
int count, key;
|
||||
static void
|
||||
_rl_vi_append_forward (key)
|
||||
int key;
|
||||
{
|
||||
int point;
|
||||
|
||||
if (rl_point < rl_end)
|
||||
{
|
||||
if (MB_CUR_MAX == 1 || rl_byte_oriented)
|
||||
rl_point++;
|
||||
else
|
||||
{
|
||||
int point = rl_point;
|
||||
point = rl_point;
|
||||
rl_forward_char (1, key);
|
||||
if (point == rl_point)
|
||||
rl_point = rl_end;
|
||||
}
|
||||
}
|
||||
rl_vi_insertion_mode (1, key);
|
||||
}
|
||||
|
||||
int
|
||||
rl_vi_append_mode (count, key)
|
||||
int count, key;
|
||||
{
|
||||
_rl_vi_append_forward (key);
|
||||
rl_vi_start_inserting (key, 1, rl_arg_sign);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -631,7 +653,7 @@ _rl_vi_save_insert (up)
|
||||
{
|
||||
int len, start, end;
|
||||
|
||||
if (up == 0)
|
||||
if (up == 0 || up->what != UNDO_INSERT)
|
||||
{
|
||||
if (vi_insert_buffer_size >= 1)
|
||||
vi_insert_buffer[0] = '\0';
|
||||
@@ -820,6 +842,15 @@ rl_vi_put (count, key)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
_rl_vi_backup ()
|
||||
{
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
|
||||
else
|
||||
rl_point--;
|
||||
}
|
||||
|
||||
int
|
||||
rl_vi_check ()
|
||||
{
|
||||
|
||||
+38
-7
@@ -109,12 +109,16 @@ static int vi_mark_chars['z' - 'a' + 1];
|
||||
static void _rl_vi_stuff_insert PARAMS((int));
|
||||
static void _rl_vi_save_insert PARAMS((UNDO_LIST *));
|
||||
|
||||
static void _rl_vi_backup PARAMS((void));
|
||||
|
||||
static int _rl_vi_arg_dispatch PARAMS((int));
|
||||
static int rl_digit_loop1 PARAMS((void));
|
||||
|
||||
static int _rl_vi_set_mark PARAMS((void));
|
||||
static int _rl_vi_goto_mark PARAMS((void));
|
||||
|
||||
static void _rl_vi_append_forward PARAMS((int));
|
||||
|
||||
static int _rl_vi_callback_getchar PARAMS((char *, int));
|
||||
|
||||
#if defined (READLINE_CALLBACKS)
|
||||
@@ -205,7 +209,16 @@ rl_vi_redo (count, c)
|
||||
_rl_vi_stuff_insert (count);
|
||||
/* And back up point over the last character inserted. */
|
||||
if (rl_point > 0)
|
||||
rl_point--;
|
||||
_rl_vi_backup ();
|
||||
}
|
||||
/* Ditto for redoing an insert with `a', but move forward a character first
|
||||
like the `a' command does. */
|
||||
else if (_rl_vi_last_command == 'a' && vi_insert_buffer && *vi_insert_buffer)
|
||||
{
|
||||
_rl_vi_append_forward ('a');
|
||||
_rl_vi_stuff_insert (count);
|
||||
if (rl_point > 0)
|
||||
_rl_vi_backup ();
|
||||
}
|
||||
else
|
||||
r = _rl_dispatch (_rl_vi_last_command, _rl_keymap);
|
||||
@@ -575,23 +588,32 @@ rl_vi_insert_beg (count, key)
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
rl_vi_append_mode (count, key)
|
||||
int count, key;
|
||||
static void
|
||||
_rl_vi_append_forward (key)
|
||||
int key;
|
||||
{
|
||||
int point;
|
||||
|
||||
if (rl_point < rl_end)
|
||||
{
|
||||
if (MB_CUR_MAX == 1 || rl_byte_oriented)
|
||||
rl_point++;
|
||||
else
|
||||
{
|
||||
int point = rl_point;
|
||||
point = rl_point;
|
||||
rl_forward_char (1, key);
|
||||
if (point == rl_point)
|
||||
rl_point = rl_end;
|
||||
}
|
||||
}
|
||||
rl_vi_insertion_mode (1, key);
|
||||
}
|
||||
|
||||
int
|
||||
rl_vi_append_mode (count, key)
|
||||
int count, key;
|
||||
{
|
||||
_rl_vi_append_forward (key);
|
||||
rl_vi_start_inserting (key, 1, rl_arg_sign);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -820,6 +842,15 @@ rl_vi_put (count, key)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
_rl_vi_backup ()
|
||||
{
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
|
||||
else
|
||||
rl_point--;
|
||||
}
|
||||
|
||||
int
|
||||
rl_vi_check ()
|
||||
{
|
||||
@@ -1111,7 +1142,7 @@ int
|
||||
rl_vi_rubout (count, key)
|
||||
int count, key;
|
||||
{
|
||||
int p, opoint;
|
||||
int opoint;
|
||||
|
||||
if (count < 0)
|
||||
return (rl_vi_delete (-count, key));
|
||||
|
||||
@@ -2907,7 +2907,7 @@ add_nestret:
|
||||
if (open == ch) /* undo previous increment */
|
||||
count--;
|
||||
if (ch == '(') /* ) */
|
||||
nestret = parse_matched_pair (0, '(', ')', &nestlen, rflags);
|
||||
nestret = parse_matched_pair (0, '(', ')', &nestlen, rflags & ~P_DQUOTE);
|
||||
else if (ch == '{') /* } */
|
||||
nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags);
|
||||
else if (ch == '[') /* ] */
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
# Set of available languages.
|
||||
en@quot en@boldquot
|
||||
en@quot en@boldquot ru
|
||||
|
||||
@@ -1533,9 +1533,10 @@ set_shell_name (argv0)
|
||||
any startup files; just try to be more like /bin/sh. */
|
||||
shell_name = argv0 ? base_pathname (argv0) : PROGRAM;
|
||||
|
||||
if (*shell_name == '-')
|
||||
if (argv0 && *argv0 == '-')
|
||||
{
|
||||
shell_name++;
|
||||
if (*shell_name == '-')
|
||||
shell_name++;
|
||||
login_shell++;
|
||||
}
|
||||
|
||||
|
||||
@@ -1208,7 +1208,7 @@ run_wordexp (words)
|
||||
wl = global_command->value.Simple->words;
|
||||
if (protected_mode)
|
||||
for (tl = wl; tl; tl = tl->next)
|
||||
tl->word->flags |= W_NOCOMSUB;
|
||||
tl->word->flags |= W_NOCOMSUB|W_NOPROCSUB;
|
||||
result = wl ? expand_words_no_vars (wl) : (WORD_LIST *)0;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -0,0 +1,570 @@
|
||||
/* sig.c - interface for shell signal handlers and signal initialization. */
|
||||
|
||||
/* Copyright (C) 1994-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#if defined (JOB_CONTROL)
|
||||
#include "jobs.h"
|
||||
#endif /* JOB_CONTROL */
|
||||
#include "siglist.h"
|
||||
#include "sig.h"
|
||||
#include "trap.h"
|
||||
|
||||
#include "builtins/common.h"
|
||||
|
||||
#if defined (READLINE)
|
||||
# include "bashline.h"
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "bashhist.h"
|
||||
#endif
|
||||
|
||||
extern int last_command_exit_value;
|
||||
extern int last_command_exit_signal;
|
||||
extern int return_catch_flag;
|
||||
extern int loop_level, continuing, breaking;
|
||||
extern int parse_and_execute_level, shell_initialized;
|
||||
|
||||
/* Non-zero after SIGINT. */
|
||||
int interrupt_state;
|
||||
|
||||
/* Non-zero after SIGWINCH */
|
||||
volatile int sigwinch_received = 0;
|
||||
|
||||
/* The environment at the top-level R-E loop. We use this in
|
||||
the case of error return. */
|
||||
procenv_t top_level;
|
||||
|
||||
#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
|
||||
/* The signal masks that this shell runs with. */
|
||||
sigset_t top_level_mask;
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
/* When non-zero, we throw_to_top_level (). */
|
||||
int interrupt_immediately = 0;
|
||||
|
||||
#if defined (SIGWINCH)
|
||||
static SigHandler *old_winch = (SigHandler *)SIG_DFL;
|
||||
#endif
|
||||
|
||||
static void initialize_shell_signals __P((void));
|
||||
|
||||
void
|
||||
initialize_signals (reinit)
|
||||
int reinit;
|
||||
{
|
||||
initialize_shell_signals ();
|
||||
initialize_job_signals ();
|
||||
#if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL)
|
||||
if (reinit == 0)
|
||||
initialize_siglist ();
|
||||
#endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */
|
||||
}
|
||||
|
||||
/* A structure describing a signal that terminates the shell if not
|
||||
caught. The orig_handler member is present so children can reset
|
||||
these signals back to their original handlers. */
|
||||
struct termsig {
|
||||
int signum;
|
||||
SigHandler *orig_handler;
|
||||
int orig_flags;
|
||||
};
|
||||
|
||||
#define NULL_HANDLER (SigHandler *)SIG_DFL
|
||||
|
||||
/* The list of signals that would terminate the shell if not caught.
|
||||
We catch them, but just so that we can write the history file,
|
||||
and so forth. */
|
||||
static struct termsig terminating_signals[] = {
|
||||
#ifdef SIGHUP
|
||||
{ SIGHUP, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGINT
|
||||
{ SIGINT, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGILL
|
||||
{ SIGILL, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGTRAP
|
||||
{ SIGTRAP, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGIOT
|
||||
{ SIGIOT, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGDANGER
|
||||
{ SIGDANGER, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGEMT
|
||||
{ SIGEMT, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGFPE
|
||||
{ SIGFPE, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGBUS
|
||||
{ SIGBUS, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGSEGV
|
||||
{ SIGSEGV, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGSYS
|
||||
{ SIGSYS, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGPIPE
|
||||
{ SIGPIPE, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGALRM
|
||||
{ SIGALRM, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGTERM
|
||||
{ SIGTERM, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGXCPU
|
||||
{ SIGXCPU, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGXFSZ
|
||||
{ SIGXFSZ, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGVTALRM
|
||||
{ SIGVTALRM, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#ifdef SIGPROF
|
||||
{ SIGPROF, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SIGLOST
|
||||
{ SIGLOST, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGUSR1
|
||||
{ SIGUSR1, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGUSR2
|
||||
{ SIGUSR2, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
};
|
||||
|
||||
#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig))
|
||||
|
||||
#define XSIG(x) (terminating_signals[x].signum)
|
||||
#define XHANDLER(x) (terminating_signals[x].orig_handler)
|
||||
#define XSAFLAGS(x) (terminating_signals[x].orig_flags)
|
||||
|
||||
static int termsigs_initialized = 0;
|
||||
|
||||
/* Initialize signals that will terminate the shell to do some
|
||||
unwind protection. For non-interactive shells, we only call
|
||||
this when a trap is defined for EXIT (0). */
|
||||
void
|
||||
initialize_terminating_signals ()
|
||||
{
|
||||
register int i;
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
struct sigaction act, oact;
|
||||
#endif
|
||||
|
||||
if (termsigs_initialized)
|
||||
return;
|
||||
|
||||
/* The following code is to avoid an expensive call to
|
||||
set_signal_handler () for each terminating_signals. Fortunately,
|
||||
this is possible in Posix. Unfortunately, we have to call signal ()
|
||||
on non-Posix systems for each signal in terminating_signals. */
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
act.sa_handler = termination_unwind_protect;
|
||||
act.sa_flags = 0;
|
||||
sigemptyset (&act.sa_mask);
|
||||
sigemptyset (&oact.sa_mask);
|
||||
for (i = 0; i < TERMSIGS_LENGTH; i++)
|
||||
sigaddset (&act.sa_mask, XSIG (i));
|
||||
for (i = 0; i < TERMSIGS_LENGTH; i++)
|
||||
{
|
||||
/* If we've already trapped it, don't do anything. */
|
||||
if (signal_is_trapped (XSIG (i)))
|
||||
continue;
|
||||
|
||||
sigaction (XSIG (i), &act, &oact);
|
||||
XHANDLER(i) = oact.sa_handler;
|
||||
XSAFLAGS(i) = oact.sa_flags;
|
||||
/* Don't do anything with signals that are ignored at shell entry
|
||||
if the shell is not interactive. */
|
||||
if (!interactive_shell && XHANDLER (i) == SIG_IGN)
|
||||
{
|
||||
sigaction (XSIG (i), &oact, &act);
|
||||
set_signal_ignored (XSIG (i));
|
||||
}
|
||||
#if defined (SIGPROF) && !defined (_MINIX)
|
||||
if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
|
||||
sigaction (XSIG (i), &oact, (struct sigaction *)NULL);
|
||||
#endif /* SIGPROF && !_MINIX */
|
||||
}
|
||||
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
for (i = 0; i < TERMSIGS_LENGTH; i++)
|
||||
{
|
||||
/* If we've already trapped it, don't do anything. */
|
||||
if (signal_is_trapped (XSIG (i)))
|
||||
continue;
|
||||
|
||||
XHANDLER(i) = signal (XSIG (i), termination_unwind_protect);
|
||||
XSAFLAGS(i) = 0;
|
||||
/* Don't do anything with signals that are ignored at shell entry
|
||||
if the shell is not interactive. */
|
||||
if (!interactive_shell && XHANDLER (i) == SIG_IGN)
|
||||
{
|
||||
signal (XSIG (i), SIG_IGN);
|
||||
set_signal_ignored (XSIG (i));
|
||||
}
|
||||
#ifdef SIGPROF
|
||||
if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
|
||||
signal (XSIG (i), XHANDLER (i));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
termsigs_initialized = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
initialize_shell_signals ()
|
||||
{
|
||||
if (interactive)
|
||||
initialize_terminating_signals ();
|
||||
|
||||
#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
|
||||
/* All shells use the signal mask they inherit, and pass it along
|
||||
to child processes. Children will never block SIGCHLD, though. */
|
||||
sigemptyset (&top_level_mask);
|
||||
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask);
|
||||
# if defined (SIGCHLD)
|
||||
sigdelset (&top_level_mask, SIGCHLD);
|
||||
# endif
|
||||
#endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */
|
||||
|
||||
/* And, some signals that are specifically ignored by the shell. */
|
||||
set_signal_handler (SIGQUIT, SIG_IGN);
|
||||
|
||||
if (interactive)
|
||||
{
|
||||
set_signal_handler (SIGINT, sigint_sighandler);
|
||||
set_signal_handler (SIGTERM, SIG_IGN);
|
||||
set_sigwinch_handler ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
reset_terminating_signals ()
|
||||
{
|
||||
register int i;
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
struct sigaction act;
|
||||
#endif
|
||||
|
||||
if (termsigs_initialized == 0)
|
||||
return;
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
act.sa_flags = 0;
|
||||
sigemptyset (&act.sa_mask);
|
||||
for (i = 0; i < TERMSIGS_LENGTH; i++)
|
||||
{
|
||||
/* Skip a signal if it's trapped or handled specially, because the
|
||||
trap code will restore the correct value. */
|
||||
if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
|
||||
continue;
|
||||
|
||||
act.sa_handler = XHANDLER (i);
|
||||
act.sa_flags = XSAFLAGS (i);
|
||||
sigaction (XSIG (i), &act, (struct sigaction *) NULL);
|
||||
}
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
for (i = 0; i < TERMSIGS_LENGTH; i++)
|
||||
{
|
||||
if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
|
||||
continue;
|
||||
|
||||
signal (XSIG (i), XHANDLER (i));
|
||||
}
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
}
|
||||
#undef XSIG
|
||||
#undef XHANDLER
|
||||
|
||||
/* What to do when we've been interrupted, and it is safe to handle it. */
|
||||
void
|
||||
throw_to_top_level ()
|
||||
{
|
||||
int print_newline = 0;
|
||||
|
||||
if (interrupt_state)
|
||||
{
|
||||
print_newline = 1;
|
||||
DELINTERRUPT;
|
||||
}
|
||||
|
||||
if (interrupt_state)
|
||||
return;
|
||||
|
||||
last_command_exit_signal = (last_command_exit_value > 128) ?
|
||||
(last_command_exit_value - 128) : 0;
|
||||
last_command_exit_value |= 128;
|
||||
|
||||
/* Run any traps set on SIGINT. */
|
||||
run_interrupt_trap ();
|
||||
|
||||
/* Cleanup string parser environment. */
|
||||
while (parse_and_execute_level)
|
||||
parse_and_execute_cleanup ();
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
give_terminal_to (shell_pgrp, 0);
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
|
||||
/* This should not be necessary on systems using sigsetjmp/siglongjmp. */
|
||||
sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
|
||||
#endif
|
||||
|
||||
reset_parser ();
|
||||
|
||||
#if defined (READLINE)
|
||||
if (interactive)
|
||||
bashline_reinitialize ();
|
||||
#endif /* READLINE */
|
||||
|
||||
#if defined (PROCESS_SUBSTITUTION)
|
||||
unlink_fifo_list ();
|
||||
#endif /* PROCESS_SUBSTITUTION */
|
||||
|
||||
run_unwind_protects ();
|
||||
loop_level = continuing = breaking = 0;
|
||||
return_catch_flag = 0;
|
||||
|
||||
if (interactive && print_newline)
|
||||
{
|
||||
fflush (stdout);
|
||||
fprintf (stderr, "\n");
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
/* An interrupted `wait' command in a script does not exit the script. */
|
||||
if (interactive || (interactive_shell && !shell_initialized) ||
|
||||
(print_newline && signal_is_trapped (SIGINT)))
|
||||
jump_to_top_level (DISCARD);
|
||||
else
|
||||
jump_to_top_level (EXITPROG);
|
||||
}
|
||||
|
||||
/* This is just here to isolate the longjmp calls. */
|
||||
void
|
||||
jump_to_top_level (value)
|
||||
int value;
|
||||
{
|
||||
longjmp (top_level, value);
|
||||
}
|
||||
|
||||
sighandler
|
||||
termination_unwind_protect (sig)
|
||||
int sig;
|
||||
{
|
||||
/* I don't believe this condition ever tests true. */
|
||||
if (sig == SIGINT && signal_is_trapped (SIGINT))
|
||||
run_interrupt_trap ();
|
||||
|
||||
#if defined (HISTORY)
|
||||
/* This might be unsafe, since it eventually calls functions POSIX says
|
||||
not to call from signal handlers. If it's a problem, take this code
|
||||
out. */
|
||||
if (interactive_shell && sig != SIGABRT)
|
||||
maybe_save_shell_history ();
|
||||
#endif /* HISTORY */
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
if (interactive && sig == SIGHUP)
|
||||
hangup_all_jobs ();
|
||||
end_job_control ();
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
#if defined (PROCESS_SUBSTITUTION)
|
||||
unlink_fifo_list ();
|
||||
#endif /* PROCESS_SUBSTITUTION */
|
||||
|
||||
run_exit_trap ();
|
||||
set_signal_handler (sig, SIG_DFL);
|
||||
kill (getpid (), sig);
|
||||
|
||||
SIGRETURN (0);
|
||||
}
|
||||
|
||||
/* What we really do when SIGINT occurs. */
|
||||
sighandler
|
||||
sigint_sighandler (sig)
|
||||
int sig;
|
||||
{
|
||||
#if defined (MUST_REINSTALL_SIGHANDLERS)
|
||||
signal (sig, sigint_sighandler);
|
||||
#endif
|
||||
|
||||
/* interrupt_state needs to be set for the stack of interrupts to work
|
||||
right. Should it be set unconditionally? */
|
||||
if (interrupt_state == 0)
|
||||
ADDINTERRUPT;
|
||||
|
||||
if (interrupt_immediately)
|
||||
{
|
||||
interrupt_immediately = 0;
|
||||
throw_to_top_level ();
|
||||
}
|
||||
|
||||
SIGRETURN (0);
|
||||
}
|
||||
|
||||
#if defined (SIGWINCH)
|
||||
sighandler
|
||||
sigwinch_sighandler (sig)
|
||||
int sig;
|
||||
{
|
||||
#if defined (MUST_REINSTALL_SIGHANDLERS)
|
||||
set_signal_handler (SIGWINCH, sigwinch_sighandler);
|
||||
#endif /* MUST_REINSTALL_SIGHANDLERS */
|
||||
sigwinch_received = 1;
|
||||
SIGRETURN (0);
|
||||
}
|
||||
#endif /* SIGWINCH */
|
||||
|
||||
void
|
||||
set_sigwinch_handler ()
|
||||
{
|
||||
#if defined (SIGWINCH)
|
||||
old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
unset_sigwinch_handler ()
|
||||
{
|
||||
#if defined (SIGWINCH)
|
||||
set_signal_handler (SIGWINCH, old_winch);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Signal functions used by the rest of the code. */
|
||||
#if !defined (HAVE_POSIX_SIGNALS)
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
|
||||
sigprocmask (operation, newset, oldset)
|
||||
int operation, *newset, *oldset;
|
||||
{
|
||||
int old, new;
|
||||
|
||||
if (newset)
|
||||
new = *newset;
|
||||
else
|
||||
new = 0;
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
case SIG_BLOCK:
|
||||
old = sigblock (new);
|
||||
break;
|
||||
|
||||
case SIG_SETMASK:
|
||||
sigsetmask (new);
|
||||
break;
|
||||
|
||||
default:
|
||||
internal_error (_("sigprocmask: %d: invalid operation"), operation);
|
||||
}
|
||||
|
||||
if (oldset)
|
||||
*oldset = old;
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
#else
|
||||
|
||||
#if !defined (SA_INTERRUPT)
|
||||
# define SA_INTERRUPT 0
|
||||
#endif
|
||||
|
||||
#if !defined (SA_RESTART)
|
||||
# define SA_RESTART 0
|
||||
#endif
|
||||
|
||||
SigHandler *
|
||||
set_signal_handler (sig, handler)
|
||||
int sig;
|
||||
SigHandler *handler;
|
||||
{
|
||||
struct sigaction act, oact;
|
||||
|
||||
itrace("set_signal_handler: sig = %d", sig);
|
||||
act.sa_handler = handler;
|
||||
act.sa_flags = 0;
|
||||
#if 0
|
||||
if (sig == SIGALRM)
|
||||
act.sa_flags |= SA_INTERRUPT; /* XXX */
|
||||
else
|
||||
act.sa_flags |= SA_RESTART; /* XXX */
|
||||
#endif
|
||||
sigemptyset (&act.sa_mask);
|
||||
sigemptyset (&oact.sa_mask);
|
||||
sigaction (sig, &act, &oact);
|
||||
return (oact.sa_handler);
|
||||
}
|
||||
#endif /* HAVE_POSIX_SIGNALS */
|
||||
@@ -5836,7 +5836,11 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
|
||||
|
||||
sindex = *indexp;
|
||||
t_index = ++sindex;
|
||||
name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME);
|
||||
/* ${#var} doesn't have any of the other parameter expansions on it. */
|
||||
if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */
|
||||
name = string_extract (string, &t_index, "}", EX_VARNAME);
|
||||
else
|
||||
name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME);
|
||||
|
||||
ret = 0;
|
||||
tflag = 0;
|
||||
|
||||
@@ -946,7 +946,7 @@ string_extract_verbatim (string, slen, sindex, charlist)
|
||||
len = mbstowcs (wcharlist, charlist, 0);
|
||||
if (len == -1)
|
||||
len = 0;
|
||||
wcharlist = xmalloc ((sizeof (wchar_t) * len) + 1);
|
||||
wcharlist = (wchar_t *)xmalloc ((sizeof (wchar_t) * len) + 1);
|
||||
mbstowcs (wcharlist, charlist, len);
|
||||
}
|
||||
|
||||
@@ -5836,7 +5836,11 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
|
||||
|
||||
sindex = *indexp;
|
||||
t_index = ++sindex;
|
||||
name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME);
|
||||
/* ${#var} doesn't have any of the other parameter expansions on it. */
|
||||
if (string[t_index] == '#' && legal_variable_starter (string[sindex])) /* {{ */
|
||||
name = string_extract (string, &t_index, "}", EX_VARNAME);
|
||||
else
|
||||
name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME);
|
||||
|
||||
ret = 0;
|
||||
tflag = 0;
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#if defined (HAVE_STDLIB_H)
|
||||
# include <stdlib.h>
|
||||
|
||||
+1
-1
@@ -134,7 +134,7 @@ initialize_signames ()
|
||||
signal_names[rtmin+rtcnt+1] = (char *)malloc(RTLEN);
|
||||
if (signal_names[rtmin+rtcnt+1])
|
||||
sprintf (signal_names[rtmin+rtcnt+1], "SIGRTMIN+%d", rtcnt+1);
|
||||
v }
|
||||
}
|
||||
}
|
||||
#endif /* SIGRTMIN && SIGRTMAX */
|
||||
|
||||
|
||||
+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
|
||||
|
||||
|
||||
@@ -30,3 +30,5 @@ argv[1] = <hello, $"world">
|
||||
argv[1] = <hello, \$"world">
|
||||
argv[1] = <hello, $"world">
|
||||
argv[1] = <hello, $world>
|
||||
argv[1] = <^I>
|
||||
argv[1] = <'A^IB'>
|
||||
|
||||
@@ -100,3 +100,12 @@ recho $'hello, \$"world"'
|
||||
recho $'hello, $\"world"'
|
||||
|
||||
recho "hello, $"world""
|
||||
|
||||
# ansi quoting inside double-quoted command subst - bash-3.1 bug
|
||||
function args
|
||||
{
|
||||
for a in "$@";do echo "'$a'";done
|
||||
}
|
||||
unset mytab
|
||||
recho "${mytab:-$'\t'}"
|
||||
recho "$( args $'A\tB' )"
|
||||
|
||||
@@ -114,6 +114,18 @@ int wait_signal_received;
|
||||
/* A value which can never be the target of a trap handler. */
|
||||
#define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps
|
||||
|
||||
#define GETORIGSIG(sig) \
|
||||
do { \
|
||||
original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \
|
||||
set_signal_handler (sig, original_signals[sig]); \
|
||||
if (original_signals[sig] == SIG_IGN) \
|
||||
sigmodes[sig] |= SIG_HARD_IGNORE; \
|
||||
} while (0)
|
||||
|
||||
#define GET_ORIGINAL_SIGNAL(sig) \
|
||||
if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
|
||||
GETORIGSIG(sig)
|
||||
|
||||
void
|
||||
initialize_traps ()
|
||||
{
|
||||
@@ -135,32 +147,25 @@ initialize_traps ()
|
||||
|
||||
/* Show which signals are treated specially by the shell. */
|
||||
#if defined (SIGCHLD)
|
||||
original_signals[SIGCHLD] =
|
||||
(SigHandler *) set_signal_handler (SIGCHLD, SIG_DFL);
|
||||
set_signal_handler (SIGCHLD, original_signals[SIGCHLD]);
|
||||
GETORIGSIG (SIGCHLD);
|
||||
sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
|
||||
#endif /* SIGCHLD */
|
||||
|
||||
original_signals[SIGINT] =
|
||||
(SigHandler *) set_signal_handler (SIGINT, SIG_DFL);
|
||||
set_signal_handler (SIGINT, original_signals[SIGINT]);
|
||||
GETORIGSIG (SIGINT);
|
||||
sigmodes[SIGINT] |= SIG_SPECIAL;
|
||||
|
||||
#if defined (__BEOS__)
|
||||
/* BeOS sets SIGINT to SIG_IGN! */
|
||||
original_signals[SIGINT] = SIG_DFL;
|
||||
sigmodes[SIGINT] &= ~SIG_HARD_IGNORE;
|
||||
#endif
|
||||
|
||||
original_signals[SIGQUIT] =
|
||||
(SigHandler *) set_signal_handler (SIGQUIT, SIG_DFL);
|
||||
set_signal_handler (SIGQUIT, original_signals[SIGQUIT]);
|
||||
GETORIGSIG (SIGQUIT);
|
||||
sigmodes[SIGQUIT] |= SIG_SPECIAL;
|
||||
|
||||
if (interactive)
|
||||
{
|
||||
original_signals[SIGTERM] =
|
||||
(SigHandler *)set_signal_handler (SIGTERM, SIG_DFL);
|
||||
set_signal_handler (SIGTERM, original_signals[SIGTERM]);
|
||||
GETORIGSIG (SIGTERM);
|
||||
sigmodes[SIGTERM] |= SIG_SPECIAL;
|
||||
}
|
||||
}
|
||||
@@ -489,17 +494,9 @@ set_signal (sig, string)
|
||||
{
|
||||
/* If we aren't sure of the original value, check it. */
|
||||
if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
|
||||
{
|
||||
original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL);
|
||||
set_signal_handler (sig, original_signals[sig]);
|
||||
}
|
||||
|
||||
/* Signals ignored on entry to the shell cannot be trapped or reset. */
|
||||
GETORIGSIG (sig);
|
||||
if (original_signals[sig] == SIG_IGN)
|
||||
{
|
||||
sigmodes[sig] |= SIG_HARD_IGNORE;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Only change the system signal handler if SIG_NO_TRAP is not set.
|
||||
@@ -547,25 +544,13 @@ change_signal (sig, value)
|
||||
sigmodes[sig] |= SIG_CHANGED;
|
||||
}
|
||||
|
||||
#define GET_ORIGINAL_SIGNAL(sig) \
|
||||
if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
|
||||
get_original_signal (sig)
|
||||
|
||||
static void
|
||||
get_original_signal (sig)
|
||||
int sig;
|
||||
{
|
||||
/* If we aren't sure the of the original value, then get it. */
|
||||
if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
|
||||
{
|
||||
original_signals[sig] =
|
||||
(SigHandler *) set_signal_handler (sig, SIG_DFL);
|
||||
set_signal_handler (sig, original_signals[sig]);
|
||||
|
||||
/* Signals ignored on entry to the shell cannot be trapped. */
|
||||
if (original_signals[sig] == SIG_IGN)
|
||||
sigmodes[sig] |= SIG_HARD_IGNORE;
|
||||
}
|
||||
GETORIGSIG (sig);
|
||||
}
|
||||
|
||||
/* Restore the default action for SIG; i.e., the action the shell
|
||||
|
||||
@@ -114,11 +114,25 @@ int wait_signal_received;
|
||||
/* A value which can never be the target of a trap handler. */
|
||||
#define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps
|
||||
|
||||
#define GETORIGSIG(sig) \
|
||||
do { \
|
||||
original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \
|
||||
set_signal_handler (sig, original_signals[sig]); \
|
||||
if (original_signals[sig] == SIG_IGN) \
|
||||
sigmodes[sig] |= SIG_HARD_IGNORE; \
|
||||
} while (0)
|
||||
|
||||
#define GET_ORIGINAL_SIGNAL(sig) \
|
||||
if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
|
||||
GETORIGSIG(sig)
|
||||
|
||||
void
|
||||
initialize_traps ()
|
||||
{
|
||||
register int i;
|
||||
|
||||
initialize_signames();
|
||||
|
||||
trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL;
|
||||
sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = sigmodes[ERROR_TRAP] = sigmodes[RETURN_TRAP] = SIG_INHERITED;
|
||||
original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER;
|
||||
@@ -133,32 +147,25 @@ initialize_traps ()
|
||||
|
||||
/* Show which signals are treated specially by the shell. */
|
||||
#if defined (SIGCHLD)
|
||||
original_signals[SIGCHLD] =
|
||||
(SigHandler *) set_signal_handler (SIGCHLD, SIG_DFL);
|
||||
set_signal_handler (SIGCHLD, original_signals[SIGCHLD]);
|
||||
GETORIGSIG (SIGCHLD);
|
||||
sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
|
||||
#endif /* SIGCHLD */
|
||||
|
||||
original_signals[SIGINT] =
|
||||
(SigHandler *) set_signal_handler (SIGINT, SIG_DFL);
|
||||
set_signal_handler (SIGINT, original_signals[SIGINT]);
|
||||
GETORIGSIG (SIGINT);
|
||||
sigmodes[SIGINT] |= SIG_SPECIAL;
|
||||
|
||||
#if defined (__BEOS__)
|
||||
/* BeOS sets SIGINT to SIG_IGN! */
|
||||
original_signals[SIGINT] = SIG_DFL;
|
||||
sigmodes[SIGINT] &= ~SIG_HARD_IGNORE;
|
||||
#endif
|
||||
|
||||
original_signals[SIGQUIT] =
|
||||
(SigHandler *) set_signal_handler (SIGQUIT, SIG_DFL);
|
||||
set_signal_handler (SIGQUIT, original_signals[SIGQUIT]);
|
||||
GETORIGSIG (SIGQUIT);
|
||||
sigmodes[SIGQUIT] |= SIG_SPECIAL;
|
||||
|
||||
if (interactive)
|
||||
{
|
||||
original_signals[SIGTERM] =
|
||||
(SigHandler *)set_signal_handler (SIGTERM, SIG_DFL);
|
||||
set_signal_handler (SIGTERM, original_signals[SIGTERM]);
|
||||
GETORIGSIG (SIGTERM);
|
||||
sigmodes[SIGTERM] |= SIG_SPECIAL;
|
||||
}
|
||||
}
|
||||
@@ -545,25 +552,13 @@ change_signal (sig, value)
|
||||
sigmodes[sig] |= SIG_CHANGED;
|
||||
}
|
||||
|
||||
#define GET_ORIGINAL_SIGNAL(sig) \
|
||||
if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
|
||||
get_original_signal (sig)
|
||||
|
||||
static void
|
||||
get_original_signal (sig)
|
||||
int sig;
|
||||
{
|
||||
/* If we aren't sure the of the original value, then get it. */
|
||||
if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
|
||||
{
|
||||
original_signals[sig] =
|
||||
(SigHandler *) set_signal_handler (sig, SIG_DFL);
|
||||
set_signal_handler (sig, original_signals[sig]);
|
||||
|
||||
/* Signals ignored on entry to the shell cannot be trapped. */
|
||||
if (original_signals[sig] == SIG_IGN)
|
||||
sigmodes[sig] |= SIG_HARD_IGNORE;
|
||||
}
|
||||
GETORIGSIG (sig);
|
||||
}
|
||||
|
||||
/* Restore the default action for SIG; i.e., the action the shell
|
||||
|
||||
Reference in New Issue
Block a user