commit bash-20060112 snapshot

This commit is contained in:
Chet Ramey
2011-12-03 22:43:58 -05:00
parent 20587658e9
commit 11a6f9a95f
40 changed files with 11605 additions and 629 deletions
+119 -3
View File
@@ -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
View File
@@ -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
+2
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+15 -20
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+137 -29
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+141 -29
View File
@@ -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
+4 -2
View File
@@ -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
+4 -4
View File
@@ -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 -2
View File
@@ -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
+1 -1
View File
@@ -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);
}
+570
View File
@@ -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 */
+4 -1
View File
@@ -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)
+701
View File
@@ -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
View File
@@ -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
View File
@@ -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));
+1 -1
View File
@@ -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
View File
@@ -1,2 +1,2 @@
# Set of available languages.
en@quot en@boldquot
en@quot en@boldquot ru
+2560
View File
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -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++;
}
+1 -1
View File
@@ -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
+570
View File
@@ -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 */
+5 -1
View File
@@ -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;
+6 -2
View File
@@ -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;
+3
View File
@@ -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
View File
@@ -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
View File
@@ -1,4 +1,4 @@
BUILD_DIR=/usr/local/build/chet/bash/bash-current
BUILD_DIR=/usr/local/build/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
+2
View File
@@ -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'>
+9
View File
@@ -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' )"
+20 -35
View File
@@ -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
+20 -25
View File
@@ -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