]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20060112 snapshot
authorChet Ramey <chet.ramey@case.edu>
Sun, 4 Dec 2011 03:43:58 +0000 (22:43 -0500)
committerChet Ramey <chet.ramey@case.edu>
Sun, 4 Dec 2011 03:43:58 +0000 (22:43 -0500)
40 files changed:
CWRU/CWRU.chlog
CWRU/CWRU.chlog~
MANIFEST
bashjmp.h
doc/bash.1
doc/bash.1.orig
doc/bash.1~
doc/bashref.texi
doc/bashref.texi~
doc/version.texi
doc/version.texi~
execute_cmd.c~
jobs.c
jobs.c.save1 [new file with mode: 0644]
jobs.c~
lib/readline/doc/rltech.texi
lib/readline/doc/rltech.texi~ [new file with mode: 0644]
lib/readline/doc/version.texi
lib/readline/doc/version.texi~
lib/readline/input.c
lib/readline/input.c~ [new file with mode: 0644]
lib/readline/terminal.c
lib/readline/terminal.c~ [new file with mode: 0644]
lib/readline/vi_mode.c
lib/readline/vi_mode.c~
parse.y
po/LINGUAS
po/ru.po [new file with mode: 0644]
shell.c
shell.c~
sig.c~ [new file with mode: 0644]
subst.c
subst.c~
support/mksignames.c
support/signames.c
tests/RUN-ONE-TEST
tests/nquote.right
tests/nquote.tests
trap.c
trap.c~

index 18f19885b739501404bce7698ca56259823d8300..9c5d11a488908b723000c7e16618d9b0f6bcd74d 100644 (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>
index 0d0223d4f8f62a9c9051455ba2a9b1af01a2b7dd..c2036f7143ae4080b7afee7395fca0e8bf8946ba 100644 (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
index ecf28852e1437436f56698c8c9e96bf7f50d3094..b0f18e6a9c0fbc365f015b730e154a44c19be7f0 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -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
index 12173e1a95e949f580569ef0c2658a023df7404b..f77e7b9585b7c2595ea31ab71a5e5747588a6d5f 100644 (file)
--- a/bashjmp.h
+++ b/bashjmp.h
@@ -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_ */
index e0843028887d5eb25c26cc65aff73752b453dcca..4c3a929f6f407b832359dd6b54de33860b8a1c22 100644 (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.
index 9de04a74208e8105fca9193ad642a0ce76aaeb4b..828ec966bfa3114edda3f01d6e88a22220395706 100644 (file)
@@ -1,17 +1,17 @@
-\"
+.\"
 .\" MAN PAGE COMMENTS to
 .\"
 .\"    Chet Ramey
 .\"    Information Network Services
 .\"    Case Western Reserve University
-.\"    chet@po.cwru.edu
+.\"    chet@po.CWRU.Edu
 .\"
-.\"    Last Change: Wed Dec 28 19:58:45 EST 2005
+.\"    Last Change: Mon Apr 14 17:57:24 EDT 2003
 .\"
 .\" 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 "2003 April 14" "GNU Bash-3.0"
 .\"
 .\" There's some problem with having a `@'
 .\" in a tagged paragraph with the BSD man macros.
@@ -51,8 +51,8 @@ bash \- GNU Bourne-Again SHell
 [options]
 [file]
 .SH COPYRIGHT
-.if n Bash is Copyright (C) 1989-2005 by the Free Software Foundation, Inc.
-.if t Bash is Copyright \(co 1989-2005 by the Free Software Foundation, Inc.
+.if n Bash is Copyright (C) 1989-2002 by the Free Software Foundation, Inc.
+.if t Bash is Copyright \(co 1989-2002 by the Free Software Foundation, Inc.
 .SH DESCRIPTION
 .B Bash
 is an \fBsh\fR-compatible command language interpreter that
@@ -64,8 +64,6 @@ shells (\fBksh\fP and \fBcsh\fP).
 .B Bash
 is intended to be a conformant implementation of the IEEE
 POSIX Shell and Tools specification (IEEE Working Group 1003\.2).
-.B Bash
-can be configured to be POSIX-conformant by default.
 .SH OPTIONS
 In addition to the single-character shell options documented in the
 description of the \fBset\fR builtin command, \fBbash\fR
@@ -117,7 +115,7 @@ when invoking an interactive shell.
 .TP
 .B \-D
 A list of all double-quoted strings preceded by \fB$\fP
-is printed on the standard output.
+is printed on the standard ouput.
 These are the strings that
 are subject to language translation when the current locale
 is not \fBC\fP or \fBPOSIX\fP.
@@ -156,13 +154,11 @@ single-character options to be recognized.
 .TP
 .B \-\-debugger
 Arrange for the debugger profile to be executed before the shell
-starts.
-Turns on extended debugging mode (see the description of the
+starts.  Turns on extended debugging mode (see the description of the
 .B extdebug
 option to the
 .B shopt
-builtin below)
-and shell function tracing (see the description of the
+builtin below) and shell function tracing (see the description of the
 \fB\-o functrace\fP option to the
 .B set
 builtin below).
@@ -273,7 +269,7 @@ An \fIinteractive\fP shell is one started without non-option arguments
 and without the
 .B \-c
 option
-whose standard input and error are
+whose standard input and output are
 both connected to terminals (as determined by
 .IR isatty (3)),
 or one started with the
@@ -491,6 +487,7 @@ command:
 .if n ! case  do done elif else esac fi for function if in select then until while { } time [[ ]]
 .if t !    case    do    done    elif    else    esac    fi    for    function    if    in    select    then    until    while    {    }    time    [[    ]]
 .if t .RE
+.RE
 .SH "SHELL GRAMMAR"
 .SS Simple Commands
 .PP
@@ -524,15 +521,12 @@ command (see
 .B REDIRECTION
 below).
 .PP
-The return status of a pipeline is the exit status of the last
-command, unless the \fBpipefail\fP option is enabled.
-If \fBpipefail\fP is enabled, the pipeline's return status is the
-value of the last (rightmost) command to exit with a non-zero status,
-or zero if all commands exit successfully.
 If the reserved word
 .B !
-precedes a pipeline, the exit status of that pipeline is the logical
-negation of the exit status as described above.
+precedes a pipeline, the exit status of that
+pipeline is the logical NOT of the exit status of the last command.
+Otherwise, the status of the pipeline is the exit status of the last
+command.
 The shell waits for all commands in the pipeline to
 terminate before returning a value.
 .PP
@@ -627,11 +621,7 @@ executed in the list.
 A \fIcompound command\fP is one of the following:
 .TP
 (\fIlist\fP)
-\fIlist\fP is executed in a subshell environment (see
-.SM
-\fBCOMMAND EXECUTION ENVIRONMENT\fP
-below).
-Variable assignments and builtin
+\fIlist\fP is executed in a subshell.  Variable assignments and builtin
 commands that affect the shell's environment do not remain in effect
 after the command completes.  The return status is the exit status of
 \fIlist\fP.
@@ -673,36 +663,12 @@ as primaries.
 When the \fB==\fP and \fB!=\fP operators are used, the string to the
 right of the operator is considered a pattern and matched according
 to the rules described below under \fBPattern Matching\fP.
-If the shell option
-.B nocasematch
-is enabled, the match is performed without regard to the case
-of alphabetic characters.
-The return value is 0 if the string matches (\fB==\fP) or does not match
-(\fB!=\fP) the pattern, and 1 otherwise.
+The return value is 0 if the string matches or does not match
+the pattern, respectively, and 1 otherwise.
 Any part of the pattern may be quoted to force it to be matched as a
 string.
 .if t .sp 0.5
 .if n .sp 1
-An additional binary operator, \fB=~\fP, is available, with the same
-precedence as \fB==\fP and \fB!=\fP.
-When it is used, the string to the right of the operator is considered
-an extended regular expression and matched accordingly (as in \fIregex\fP(3)).  
-The return value is 0 if the string matches
-the pattern, and 1 otherwise.
-If the regular expression is syntactically incorrect, the conditional
-expression's return value is 2.
-If the shell option
-.B nocasematch
-is enabled, the match is performed without regard to the case
-of alphabetic characters.
-Substrings matched by parenthesized subexpressions within the regular
-expression are saved in the array variable \fBBASH_REMATCH\fP.
-The element of \fBBASH_REMATCH\fP with index 0 is the portion of the string
-matching the entire regular expression.
-The element of \fBBASH_REMATCH\fP with index \fIn\fP is the portion of the
-string matching the \fIn\fPth parenthesized subexpression.
-.if t .sp 0.5
-.if n .sp 1
 Expressions may be combined using the following operators, listed
 in decreasing order of precedence:
 .if t .sp 0.5
@@ -806,18 +772,7 @@ A \fBcase\fP command first expands \fIword\fP, and tries to match
 it against each \fIpattern\fP in turn, using the same matching rules
 as for pathname expansion (see
 .B Pathname Expansion
-below).
-The \fIword\fP is expanded using tilde
-expansion, parameter and variable expansion, arithmetic substituion,
-command substitution, process substitution and quote removal.
-Each \fIpattern\fP examined is expanded using tilde
-expansion, parameter and variable expansion, arithmetic substituion,
-command substitution, and process substitution.
-If the shell option
-.B nocasematch
-is enabled, the match is performed without regard to the case
-of alphabetic characters.
-When a match is found, the
+below).  When a match is found, the
 corresponding \fIlist\fP is executed.  After the first match, no
 subsequent matches are attempted.  The exit status is zero if no
 pattern matches.  Otherwise, it is the exit status of the
@@ -856,32 +811,15 @@ The exit status of the \fBwhile\fP and \fBuntil\fP commands
 is the exit status
 of the last \fBdo\fP \fIlist\fP command executed, or zero if
 none was executed.
-.SS Shell Function Definitions
-.PP
-A shell function is an object that is called like a simple command and
-executes a compound command with a new set of positional parameters.
-Shell functions are declared as follows:
-.TP
-[ \fBfunction\fP ] \fIname\fP () \fIcompound\-command\fP [\fIredirection\fP]
-This defines a function named \fIname\fP.
-The reserved word \fBfunction\fP is optional.
-If the \fBfunction\fP reserved word is supplied, the parentheses are optional.
-The \fIbody\fP of the function is the compound command
-.I compound\-command 
-(see \fBCompound Commands\fP above).
-That command is usually a \fIlist\fP of commands between { and }, but
-may be any command listed under \fBCompound Commands\fP above.
-\fIcompound\-command\fP is executed whenever \fIname\fP is specified as the
-name of a simple command.
-Any redirections (see
-.SM
-.B REDIRECTION
-below) specified when a function is defined are performed
-when the function is executed.
-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
-last command executed in the body.  (See
+.TP
+[ \fBfunction\fP ] \fIname\fP () { \fIlist\fP; }
+This defines a function named \fIname\fP.  The \fIbody\fP of the
+function is the
+.I list
+of commands between { and }.  This list
+is executed whenever \fIname\fP is specified as the
+name of a simple command.  The exit status of a function is
+the exit status of the last command executed in the body.  (See
 .SM
 .B FUNCTIONS
 below.)
@@ -914,11 +852,7 @@ Each of the \fImetacharacters\fP listed above under
 has special meaning to the shell and must be quoted if it is to
 represent itself.
 .PP
-When the command history expansion facilities are being used
-(see
-.SM
-.B HISTORY EXPANSION
-below), the
+When the command history expansion facilities are being used, the
 \fIhistory expansion\fP character, usually \fB!\fP, must be quoted
 to prevent history expansion.
 .PP
@@ -942,9 +876,8 @@ Enclosing characters in double quotes preserves the literal value
 of all characters within the quotes, with the exception of
 .BR $ ,
 .BR ` ,
-.BR \e ,
-and, when history expansion is enabled,
-.BR ! .
+and
+.BR \e .
 The characters
 .B $
 and
@@ -960,12 +893,8 @@ or
 .BR <newline> .
 A double quote may be quoted within double quotes by preceding it with
 a backslash.
-If enabled, history expansion will be performed unless an
-.B !
-appearing in double quotes is escaped using a backslash.
-The backslash preceding the
-.B !
-is not removed.
+When command history is being used, the double quote may not be used to
+quote the history expansion character.
 .PP
 The special parameters
 .B *
@@ -979,7 +908,7 @@ below).
 .PP
 Words of the form \fB$\fP'\fIstring\fP' 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
+as specifed by the ANSI C standard.  Backslash escape sequences, if
 present, are decoded as follows:
 .RS
 .PD 0
@@ -1096,7 +1025,6 @@ of \fB"$@"\fP as explained below under
 .BR "Special Parameters" .
 Pathname expansion is not performed.
 Assignment statements may also appear as arguments to the
-.BR alias ,
 .BR declare ,
 .BR typeset ,
 .BR export ,
@@ -1104,20 +1032,6 @@ Assignment statements may also appear as arguments to the
 and
 .B local
 builtin commands.
-.PP
-In the context where an assignment statement is assigning a value
-to a shell variable or array index, the += operator can be used to
-append to or add to the variable's previous value.
-When += is applied to a variable for which the integer attribute has been
-set, \fIvalue\fP is evaluated as an arithmetic expression and added to the
-variable's current value, which is also evaluated.
-When += is applied to an array variable using compound assignment (see
-.B Arrays
-below), the
-variable's value is not unset (as it is when using =), and new values are
-appended to the array beginning at one greater than the array's maximum index.
-When applied to a string-valued variable, \fIvalue\fP is expanded and
-appended to the variable's value.
 .SS Positional Parameters
 .PP
 A
@@ -1172,10 +1086,6 @@ Expands to the positional parameters, starting from one.  When the
 expansion occurs within double quotes, each parameter expands to a
 separate word.  That is, "\fB$@\fP" is equivalent to
 "\fB$1\fP" "\fB$2\fP" ...
-If the double-quoted expansion occurs within a word, the expansion of
-the first parameter is joined with the beginning part of the original
-word, and the expansion of the last parameter is joined with the last
-part of the original word.
 When there are no positional parameters, "\fB$@\fP" and 
 .B $@
 expand to nothing (i.e., they are removed).
@@ -1224,13 +1134,12 @@ to the file name used to invoke
 as given by argument zero.
 .TP
 .B _
-At shell startup, set to the absolute pathname used to invoke the
-shell or shell script being executed as passed in the environment
-or argument list.
+At shell startup, set to the absolute file name of the shell or shell
+script being executed as passed in the argument list.
 Subsequently, expands to the last argument to the previous command,
 after expansion.
-Also set to the full pathname used to invoke each command executed
-and placed in the environment exported to that command.
+Also set to the full file name of each command executed and placed in
+the environment exported to that command.
 When checking mail, this parameter holds the name of the mail file
 currently being checked.
 .PD
@@ -1246,18 +1155,11 @@ Expands to the full file name used to invoke this instance of
 .TP
 .B BASH_ARGC
 An array variable whose values are the number of parameters in each
-frame of the current bash execution call stack.
-The number of
+frame of the current bash execution call stack.  The number of
 parameters to the current subroutine (shell function or script executed
-with \fB.\fP or \fBsource\fP) is at the top of the stack.
-When a subroutine is executed, the number of parameters passed is pushed onto
+with \fB.\fP or \fBsource\fP) is at the top of the stack.  When a
+subroutine is executed, the number of parameters passed is pushed onto
 \fBBASH_ARGC\fP.
-The shell sets \fBBASH_ARGC\fP only when in extended debugging mode
-(see the description of the
-.B extdebug
-option to the
-.B shopt
-builtin below)
 .TP
 .B BASH_ARGV
 An array variable containing all of the parameters in the current bash
@@ -1265,12 +1167,6 @@ execution call stack.  The final parameter of the last subroutine call
 is at the top of the stack; the first parameter of the initial call is
 at the bottom.  When a subroutine is executed, the parameters supplied
 are pushed onto \fBBASH_ARGV\fP.
-The shell sets \fBBASH_ARGV\fP only when in extended debugging mode
-(see the description of the
-.B extdebug
-option to the
-.B shopt
-builtin below)
 .TP
 .B BASH_COMMAND
 The command currently being executed or about to be executed, unless the
@@ -1282,21 +1178,12 @@ The command argument to the \fB\-c\fP invocation option.
 .TP
 .B BASH_LINENO
 An array variable whose members are the line numbers in source files
-corresponding to each member of \fBFUNCNAME\fP.
+corresponding to each member of @var{FUNCNAME}.
 \fB${BASH_LINENO[\fP\fI$i\fP\fB]}\fP is the line number in the source
-file where \fB${FUNCNAME[\fP\fI$ifP\fB]}\fP was called.
-The corresponding source file name is \fB${BASH_SOURCE[\fP\fI$i\fP\fB]}\fB.
+file where \fB${FUNCNAME[\fP\fI$i + 1\fP\fB]}\fP was called.
+The corresponding source file name is \fB${BASH_SOURCE[\fP\fI$i + 1\fP\fB]}\fB.
 Use \fBLINENO\fP to obtain the current line number.
 .TP
-.B BASH_REMATCH
-An array variable whose members are assigned by the \fB=~\fP binary
-operator to the \fB[[\fP conditional command.
-The element with index 0 is the portion of the string
-matching the entire regular expression.
-The element with index \fIn\fP is the portion of the
-string matching the \fIn\fPth parenthesized subexpression.
-This variable is read-only.
-.TP
 .B BASH_SOURCE
 An array variable whose members are the source filenames corresponding
 to the elements in the \fBFUNCNAME\fP array variable.
@@ -1717,13 +1604,6 @@ The number of commands to remember in the command history (see
 .B HISTORY
 below).  The default value is 500.
 .TP
-.B HISTTIMEFORMAT
-If this variable is set and not null, its value is used as a format string
-for \fIstrftime\fP(3) to print the time stamp associated with each history
-entry displayed by the \fBhistory\fP builtin.
-If this variable is set, time stamps are written to the history file so
-they may be preserved across shell sessions.
-.TP
 .B HOME
 The home directory of the current user; the default argument for the
 \fBcd\fP builtin command.
@@ -1881,8 +1761,8 @@ The default path is system-dependent,
 and is set by the administrator who installs
 .BR bash .
 A common value is
-.if t \f(CW/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin\fP.
-.if n ``/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin''.
+.if t \f(CW/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:.\fP.
+.if n ``/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:.''.
 .TP
 .B POSIXLY_CORRECT
 If this variable is in the environment when \fBbash\fP starts, the shell
@@ -1930,12 +1810,6 @@ displays during an execution trace.  The first character of
 is replicated multiple times, as necessary, to indicate multiple
 levels of indirection.  The default is ``\fB+ \fP''.
 .TP
-.B SHELL
-The full pathname to the shell is kept in this environment variable.
-If it is not set when the shell starts,
-.B bash
-assigns to it the full pathname of the current user's login shell.
-.TP
 .B TIMEFORMAT
 The value of this parameter is used as a format string specifying
 how the timing information for pipelines prefixed with the
@@ -1994,10 +1868,6 @@ number of seconds to wait for input after issuing the primary prompt.
 terminates after waiting for that number of seconds if input does
 not arrive.
 .TP
-.B TMPDIR
-If set, \fBBash\fP uses its value as the name of a directory in which
-\fBBash\fP creates temporary files for the shell's use.
-.TP
 .B auto_resume
 This variable controls how the shell interacts with the user and
 job control.  If this variable is set, single word simple
@@ -2023,7 +1893,9 @@ job identifier (see
 .B JOB CONTROL
 below).  If set to any other value, the supplied string must
 be a prefix of a stopped job's name; this provides functionality
-analogous to the \fB%\fP\fIstring\fP job identifier.
+analogous to the
+.B %
+job identifier.
 .TP
 .B histchars
 The two or three characters which control history expansion
@@ -2097,12 +1969,7 @@ character of the
 .B IFS
 special variable, and ${\fIname\fP[@]} expands each element of
 \fIname\fP to a separate word.  When there are no array members,
-${\fIname\fP[@]} expands to nothing.
-If the double-quoted expansion occurs within a word, the expansion of
-the first parameter is joined with the beginning part of the original
-word, and the expansion of the last parameter is joined with the last
-part of the original word.
-This is analogous to the expansion
+${\fIname\fP[@]} expands to nothing.  This is analogous to the expansion
 of the special parameters \fB*\fP and \fB@\fP (see
 .B Special Parameters
 above).  ${#\fIname\fP[\fIsubscript\fP]} expands to the length of
@@ -2115,8 +1982,6 @@ The
 .B unset
 builtin is used to destroy arrays.  \fBunset\fP \fIname\fP[\fIsubscript\fP]
 destroys the array element at index \fIsubscript\fP.
-Care must be taken to avoid unwanted side effects caused by filename
-generation.
 \fBunset\fP \fIname\fP, where \fIname\fP is an array, or
 \fBunset\fP \fIname\fP[\fIsubscript\fP], where
 \fIsubscript\fP is \fB*\fP or \fB@\fP, removes the entire array.
@@ -2298,7 +2163,7 @@ is unchanged.
 Each variable assignment is checked for unquoted tilde-prefixes immediately
 following a
 .B :
-or the first
+or
 .BR = .
 In these cases, tilde expansion is also performed.
 Consequently, one may use file names with tildes in assignments to
@@ -2321,7 +2186,7 @@ interpreted as part of the name.
 .PP
 When braces are used, the matching ending brace is the first `\fB}\fP'
 not escaped by a backslash or within a quoted string, and not within an
-embedded arithmetic expansion, command substitution, or parameter
+embedded arithmetic expansion, command substitution, or paramter
 expansion.
 .PP
 .PD 0
@@ -2421,10 +2286,6 @@ parameters beginning at \fIoffset\fP.
 If \fIparameter\fP is an array name indexed by @ or *,
 the result is the \fIlength\fP
 members of the array beginning with ${\fIparameter\fP[\fIoffset\fP]}.
-A negative \fIoffset\fP is taken relative to one greater than the maximum
-index of the specified array.
-Note that a negative offset must be separated from the colon by at least
-one space to avoid being confused with the :- expansion.
 Substring indexing is zero-based unless the positional parameters 
 are used, in which case the indexing starts at 1.
 .TP
@@ -2531,12 +2392,17 @@ 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.
-If \Ipattern\fP begins with \fB/\fP, all matches of \fIpattern\fP are
-replaced with \fIstring\fP.  Normally only the first match is replaced.
+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 \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
@@ -2736,10 +2602,6 @@ If the
 .B nullglob
 option is set, and no matches are found,
 the word is removed.
-If the
-.B failglob
-shell option is set, and no matches are found, an error message
-is printed and the command is not executed.
 If the shell option
 .B nocaseglob
 is enabled, the match is performed without regard to the case
@@ -2764,7 +2626,6 @@ below under
 for a description of the
 .BR nocaseglob ,
 .BR nullglob ,
-.BR failglob ,
 and
 .B dotglob
 shell options.
@@ -2914,7 +2775,7 @@ Matches zero or more occurrences of the given patterns
 Matches one or more occurrences of the given patterns
 .TP
 \fB@(\fP\^\fIpattern-list\^\fP\fB)\fP
-Matches one of the given patterns
+Matches exactly one of the given patterns
 .TP
 \fB!(\fP\^\fIpattern-list\^\fP\fB)\fP
 Matches anything except one of the given patterns
@@ -3011,10 +2872,6 @@ a UDP connection to the corresponding socket.
 .RE
 .PP
 A failure to open or create a file causes the redirection to fail.
-.PP
-Redirections using file descriptors greater than 9 should be used with
-care, as they may conflict with file descriptors the shell uses
-internally.
 .SS Redirecting Input
 .PP
 Redirection of input causes the file whose name results from
@@ -3266,18 +3123,16 @@ builtin commands (see
 .SM
 .B SHELL BUILTIN COMMANDS
 below).
-The first word of each simple command, if unquoted,
+The first word of each command, if unquoted,
 is checked to see if it has an
 alias.  If so, that word is replaced by the text of the alias.
-The characters \fB/\fP, \fB$\fP, \fB`\fP, and \fB=\fP and
-any of the shell \fImetacharacters\fP or quoting characters
-listed above may not appear in an alias name.
-The replacement text may contain any valid shell input,
-including shell metacharacters.
-The first word of the replacement text is tested
+The alias name and the replacement text may contain any valid
+shell input, including the
+.I metacharacters
+listed above, with the exception that the alias name may not
+contain \fI=\fP.  The first word of the replacement text is tested
 for aliases, but a word that is identical to an alias being expanded
-is not expanded a second time.
-This means that one may alias
+is not expanded a second time.  This means that one may alias
 .B ls
 to
 .BR "ls \-F" ,
@@ -3351,7 +3206,7 @@ function become the positional parameters
 during its execution.
 The special parameter
 .B #
-is updated to reflect the change.  Special parameter 0
+is updated to reflect the change.  Positional parameter 0
 is unchanged.
 The first element of the
 .SM
@@ -3363,21 +3218,19 @@ environment are identical between a function and its caller
 with the exception that the
 .SM
 .B DEBUG
-and
-.B RETURN
-traps (see the description of the
+trap (see the description of the
 .B trap
 builtin under
 .SM
 .B SHELL BUILTIN COMMANDS
-below) are not inherited unless the function has been given the
+below) is not inherited unless the function has been given the
 \fBtrace\fP attribute (see the description of the
 .SM
 .B declare
 builtin below) or the
 \fB\-o functrace\fP shell option has been enabled with
 the \fBset\fP builtin
-(in which case all functions inherit the \fBDEBUG\fP and \fBRETURN\fP traps).
+(in which case all functions inherit the \fBDEBUG\fP trap).
 .PP
 Variables local to the function may be declared with the
 .B local
@@ -3516,7 +3369,7 @@ If \fIbase#\fP is omitted, then base 10 is used.
 The digits greater than 9 are represented by the lowercase letters,
 the uppercase letters, @, and _, in that order.
 If \fIbase\fP is less than or equal to 36, lowercase and uppercase
-letters may be used interchangeably to represent numbers between 10
+letters may be used interchangably to represent numbers between 10
 and 35.
 .PP
 Operators are evaluated in order of precedence.  Sub-expressions in
@@ -3532,9 +3385,6 @@ If any \fIfile\fP argument to one of the primaries is of the form
 If the \fIfile\fP argument to one of the primaries is one of
 \fI/dev/stdin\fP, \fI/dev/stdout\fP, or \fI/dev/stderr\fP, file
 descriptor 0, 1, or 2, respectively, is checked.
-.PP
-Unless otherwise specified, primaries that operate on files follow symbolic
-links and operate on the target of the link, rather than the link itself.
 .sp 1
 .PD 0
 .TP
@@ -3628,11 +3478,9 @@ builtin below.
 .B \-z \fIstring\fP
 True if the length of \fIstring\fP is zero.
 .TP
-\fIstring\fP
-.PD 0
-.TP
 .B \-n \fIstring\fP
-.PD
+.TP
+\fIstring\fP
 True if the length of
 .I string
 is non-zero.
@@ -3822,14 +3670,13 @@ the file creation mode mask
 shell variables and functions marked for export, along with variables
 exported for the command, passed in the environment
 .IP \(bu
-traps caught by the shell are reset to the values inherited from the
-shell's parent, and traps ignored by the shell are ignored
+traps caught by the shell are reset to the values the inherited
+from the shell's parent, and traps ignored by the shell are ignored
 .PP
 A command invoked in this separate environment cannot affect the
 shell's execution environment. 
 .PP
-Command substitution, commands grouped with parentheses,
-and asynchronous commands are invoked in a
+Command substitution and asynchronous commands are invoked in a
 subshell environment that is a duplicate of the shell environment,
 except that traps caught by the shell are reset to the values
 that the shell inherited from its parent at invocation.  Builtin
@@ -3943,7 +3790,7 @@ and
 .SM
 .BR SIGTSTP .
 .PP
-Non-builtin commands run by \fBbash\fP have signal handlers
+Synchronous jobs started by \fBbash\fP have signal handlers
 set to the values inherited by the shell from its parent.
 When job control is not in effect, asynchronous commands
 ignore
@@ -3952,7 +3799,7 @@ ignore
 and
 .SM
 .B SIGQUIT
-in addition to these inherited handlers.
+as well.
 Commands run as a result of command substitution ignore the
 keyboard-generated job control signals
 .SM
@@ -4000,9 +3847,9 @@ sends a
 .B SIGHUP
 to all jobs when an interactive login shell exits.
 .PP
-If \fBbash\fP is waiting for a command to complete and receives a signal
-for which a trap has been set, the trap will not be executed until
-the command completes. 
+When \fBbash\fP receives a signal for which a trap has been set while
+waiting for a command to complete, the trap will not be executed until
+the command completes.
 When \fBbash\fP is waiting for an asynchronous command via the \fBwait\fP
 builtin, the reception of a signal for which a trap has been set will
 cause the \fBwait\fP builtin to return immediately with an exit status
@@ -4130,8 +3977,6 @@ command), the current job is always flagged with a
 .BR + ,
 and the previous job with a
 .BR \- .
-A single % (with no accompanying job specification) also refers to the
-current job.
 .PP
 Simply naming a job can be used to bring it into the
 foreground:
@@ -4242,14 +4087,13 @@ the username of the current user
 the version of \fBbash\fP (e.g., 2.00)
 .TP
 .B \eV
-the release of \fBbash\fP, version + patch level (e.g., 2.00.0)
+the release of \fBbash\fP, version + patchelvel (e.g., 2.00.0)
 .TP
 .B \ew
-the current working directory, with \fB$HOME\fP abbreviated with a tilde
+the current working directory
 .TP
 .B \eW
-the basename of the current working directory, with \fB$HOME\fP
-abbreviated with a tilde
+the basename of the current working directory
 .TP
 .B \e!
 the history number of this command
@@ -4568,12 +4412,7 @@ file with a statement of the form
 Except where noted, readline variables can take the values
 .B On
 or
-.B Off
-(without regard to case).
-Unrecognized variable names are ignored.
-When a variable value is read, empty or null values, "on" (case-insensitive),
-and "1" are equivalent to \fBOn\fP.  All other values are equivalent to
-\fBOff\fP.
+.BR Off .
 The variables and their default values are:
 .PP
 .PD 0
@@ -4584,11 +4423,6 @@ If set to \fBnone\fP, readline never rings the bell.  If set to
 \fBvisible\fP, readline uses a visible bell if one is available.
 If set to \fBaudible\fP, readline attempts to ring the terminal's bell.
 .TP
-.B bind\-tty\-special\-chars (On)
-If set to \fBOn\fP, readline attempts to bind the control characters
-treated specially by the kernel's terminal driver to their readline
-equivalents.
-.TP
 .B comment\-begin (``#'')
 The string that is inserted when the readline
 .B insert\-comment
@@ -4642,9 +4476,9 @@ arrow keys.
 If set to \fBon\fP, tilde expansion is performed when readline
 attempts word completion.
 .TP
-.B history\-preserve\-point (Off)
+.B history-preserve-point
 If set to \fBon\fP, the history code attempts to place point at the
-same location on each history line retrieved with \fBprevious-history\fP
+same location on each history line retrived with \fBprevious-history\fP
 or \fBnext-history\fP.
 .TP
 .B horizontal\-scroll\-mode (Off)
@@ -4716,16 +4550,6 @@ set to
 words which have more than one possible completion cause the
 matches to be listed immediately instead of ringing the bell.
 .TP
-.B show\-all\-if\-unmodified (Off)
-This alters the default behavior of the completion functions in
-a fashion similar to \fBshow\-all\-if\-ambiguous\fP.
-If set to
-.BR on ,
-words which have more than one possible completion without any
-possible partial completion (the possible completions don't share
-a common prefix) cause the matches to be listed immediately instead
-of ringing the bell.
-.TP
 .B visible\-stats (Off)
 If set to \fBOn\fP, a character denoting a file's type as reported
 by \fIstat\fP(2) is appended to the filename when listing possible
@@ -4944,8 +4768,6 @@ With an argument
 insert the \fIn\fPth word from the previous command (the words
 in the previous command begin with word 0).  A negative argument
 inserts the \fIn\fPth word from the end of the previous command.
-Once the argument \fIn\fP is computed, the argument is extracted
-as if the "!\fIn\fP" history expansion had been specified.
 .TP
 .B
 yank\-last\-arg (M\-.\^, M\-_\^)
@@ -4954,8 +4776,6 @@ the previous history entry).  With an argument,
 behave exactly like \fByank\-nth\-arg\fP.
 Successive calls to \fByank\-last\-arg\fP move back through the history
 list, inserting the last argument of each line in turn.
-The history expansion facilities are used to extract the last argument,
-as if the "!$" history expansion had been specified.
 .TP
 .B shell\-expand\-line (M\-C\-e)
 Expand the line as the shell does.  This
@@ -5105,11 +4925,6 @@ Word boundaries are the same as those used by \fBbackward\-word\fP.
 Kill the word behind point, using white space as a word boundary.
 The killed text is saved on the kill-ring.
 .TP
-.B unix\-filename\-rubout
-Kill the word behind point, using white space and the slash character
-as the word boundaries.
-The killed text is saved on the kill-ring.
-.TP
 .B delete\-horizontal\-space (M\-\e)
 Delete all spaces and tabs around point.
 .TP
@@ -5368,7 +5183,7 @@ of an \fIinputrc\fP file.
 .TP
 .B dump\-macros
 Print all of the readline key sequences bound to macros and the
-strings they output.  If a numeric argument is supplied,
+strings they ouput.  If a numeric argument is supplied,
 the output is formatted in such a way that it can be made part
 of an \fIinputrc\fP file.
 .TP
@@ -5432,7 +5247,7 @@ special variable as delimiters.
 Shell quoting is honored.
 Each word is then expanded using
 brace expansion, tilde expansion, parameter and variable expansion,
-command substitution, and arithmetic expansion,
+command substitution, arithmetic expansion, and pathname expansion,
 as described above under 
 .SM
 .BR EXPANSION .
@@ -5499,21 +5314,13 @@ If the previously-applied actions do not generate any matches, and the
 \fB\-o dirnames\fP option was supplied to \fBcomplete\fP when the
 compspec was defined, directory name completion is attempted.
 .PP
-If the \fB\-o plusdirs\fP option was supplied to \fBcomplete\fP when the
-compspec was defined, directory name completion is attempted and any
-matches are added to the results of the other actions.
-.PP
 By default, if a compspec is found, whatever it generates is returned
 to the completion code as the full set of possible completions.
 The default \fBbash\fP completions are not attempted, and the readline
 default of filename completion is disabled.
-If the \fB\-o bashdefault\fP option was supplied to \fBcomplete\fP when
-the compspec was defined, the \fBbash\fP default completions are attempted
-if the compspec generates no matches.
-If the \fB\-o default\fP option was supplied to \fBcomplete\fP when the
+If the \fB-o default\fP option was supplied to \fBcomplete\fP when the
 compspec was defined, readline's default completion will be performed
-if the compspec (and, if attempted, the default \fBbash\fP completions)
-generate no matches.
+if the compspec generates no matches.
 .PP
 When a compspec indicates that directory name completion is desired,
 the programmable completion functions force readline to append a slash
@@ -5665,12 +5472,6 @@ history expansion character, which is \^\fB!\fP\^ by default.
 Only backslash (\^\fB\e\fP\^) and single quotes can quote
 the history expansion character.
 .PP
-Several characters inhibit history expansion if found immediately
-following the history expansion character, even if it is unquoted:
-space, tab, newline, carriage return, and \fB=\fP.
-If the \fBextglob\fP shell option is enabled, \fB(\fP will also
-inhibit expansion.
-.PP
 Several shell options settable with the
 .B shopt
 builtin may be used to tailor the behavior of history expansion.
@@ -5722,8 +5523,7 @@ history list.
 .B !
 Start a history substitution, except when followed by a
 .BR blank ,
-newline, carriage return, =
-or ( (when the \fBextglob\fP shell option is enabled using
+newline, = or ( (when the \fBextglob\fP shell option is enabled using
 the \fBshopt\fP builtin).
 .TP
 .B !\fIn\fR
@@ -5899,8 +5699,6 @@ section as accepting options preceded by
 accepts
 .B \-\-
 to signify the end of the options.
-For example, the \fB:\fP, \fBtrue\fP, \fBfalse\fP, and \fBtest\fP builtins
-do not accept options.
 .sp .5
 .PD 0
 .TP
@@ -5967,8 +5765,8 @@ is supplied, the name and value of the alias is printed.
 \fBAlias\fP returns true unless a \fIname\fP is given for which
 no alias has been defined.
 .TP
-\fBbg\fP [\fIjobspec\fP ...]
-Resume each suspended job \fIjobspec\fP in the background, as if it
+\fBbg\fP [\fIjobspec\fP]
+Resume the suspended job \fIjobspec\fP in the background, as if it
 had been started with
 .BR & .
 If \fIjobspec\fP is not present, the shell's notion of the
@@ -5976,8 +5774,8 @@ If \fIjobspec\fP is not present, the shell's notion of the
 .B bg
 .I jobspec
 returns 0 unless run when job control is disabled or, when run with
-job control enabled, any specified \fIjobspec\fP was not found
-or was started without job control.
+job control enabled, if \fIjobspec\fP was not found or started without
+job control.
 .TP
 \fBbind\fP [\fB\-m\fP \fIkeymap\fP] [\fB\-lpsvPSV\fP]
 .PD 0
@@ -6133,10 +5931,6 @@ option forces symbolic links to be followed.  An argument of
 is equivalent to
 .SM
 .BR $OLDPWD .
-If a non-empty directory name from \fBCDPATH\fP is used, or if
-\fB\-\fP is the first argument, and the directory change is
-successful, the absolute pathname of the new working directory is
-written to the standard output.
 The return value is true if the directory was successfully changed;
 false otherwise.
 .TP
@@ -6250,10 +6044,6 @@ beyond the simple generation of completions.
 \fIcomp-option\fP may be one of:
 .RS
 .TP 8
-.B bashdefault
-Perform the rest of the default \fBbash\fP completions if the compspec
-generates no matches.
-.TP 8
 .B default
 Use readline's default filename completion if the compspec generates
 no matches.
@@ -6269,11 +6059,6 @@ suppressing trailing spaces).  Intended to be used with shell functions.
 .B nospace
 Tell readline not to append a space (the default) to words completed at
 the end of the line.
-.TP 8
-.B plusdirs
-After any matches defined by the compspec are generated, 
-directory name completion is attempted and any
-matches are added to the results of the other actions.
 .RE
 .TP 8
 \fB\-A\fP \fIaction\fP
@@ -6476,8 +6261,7 @@ by subsequent assignment statements or unset.
 .TP
 .B \-t
 Give each \fIname\fP the \fItrace\fP attribute.
-Traced functions inherit the \fBDEBUG\fP and \fBRETURN\fP traps from
-the calling shell.
+Traced functions inherit the \fBDEBUG\fP trap from the calling shell.
 The trace attribute has no special meaning for variables.
 .TP
 .B \-x
@@ -6596,7 +6380,9 @@ The \fBxpg_echo\fP shell option may be used to
 dynamically determine whether or not \fBecho\fP expands these
 escape characters by default.
 .B echo
-does not interpret \fB\-\-\fP to mean the end of options.
+does not interpret
+.B \-\-
+to mean the end of options.
 .B echo
 interprets the following escape sequences:
 .RS
@@ -6765,8 +6551,8 @@ option is supplied, a list
 of all names that are exported in this shell is printed.
 The
 .B \-n
-option causes the export property to be removed from each
-\fIname\fP.
+option causes the export property to be removed from the
+named variables.
 If a variable name is followed by =\fIword\fP, the value of
 the variable is set to \fIword\fP.
 .B export
@@ -7058,13 +6844,7 @@ have been modified.  An argument of
 .I n
 lists only the last
 .I n
-lines.
-If the shell variable \fBHISTTIMEFORMAT\fP is set and not null,
-it is used as a format string for \fIstrftime\fP(3) to display
-the time stamp associated with each displayed history entry.
-No intervening blank is printed between the formatted time stamp
-and the history line.
-If \fIfilename\fP is supplied, it is used as the
+lines.  If \fIfilename\fP is supplied, it is used as the
 name of the history file; if not, the value of
 .SM
 .B HISTFILE
@@ -7111,8 +6891,6 @@ history list is removed before the
 are added.
 .PD
 .PP
-If the \fBHISTTIMEFORMAT\fP is set, the time stamp information
-associated with each history entry is written to the history file.
 The return value is 0 unless an invalid option is encountered, an
 error occurs while reading or writing the history file, an invalid
 \fIoffset\fP is supplied as an argument to \fB\-d\fP, or the
@@ -7187,15 +6965,18 @@ to the processes named by
 or
 .IR jobspec .
 .I sigspec
-is either a case-insensitive signal name such as
+is either a signal name such as
 .SM
 .B SIGKILL
-(with or without the
+or a signal number;
+.I signum
+is a signal number.  If
+.I sigspec
+is a signal name, the name may be
+given with or without the
 .SM
 .B SIG
-prefix) or a signal number;
-.I signum
-is a signal number.
+prefix.
 If
 .I sigspec
 is not present, then
@@ -7304,7 +7085,7 @@ is empty, a non-existent directory stack entry is specified, or the
 directory change fails.
 .RE
 .TP
-\fBprintf\fP [\fB\-v\fP \fIvar\fP] \fIformat\fP [\fIarguments\fP]
+\fBprintf\fP \fIformat\fP [\fIarguments\fP]
 Write the formatted \fIarguments\fP to the standard output under the
 control of the \fIformat\fP.
 The \fIformat\fP is a character string which contains three types of objects:
@@ -7314,15 +7095,9 @@ format specifications, each of which causes printing of the next successive
 \fIargument\fP.
 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
-beginning with \fB\e0\fP may contain up to four digits),
-and \fB%q\fP causes \fBprintf\fP to output the corresponding
+\fIargument\fP, and \fB%q\fP causes \fBprintf\fP to output the corresponding
 \fIargument\fP in a format that can be reused as shell input.
 .sp 1
-The \fB\-v\fP option causes the output to be assigned to the variable
-\fIvar\fP rather than being printed to the standard output.
-.sp 1
 The \fIformat\fP is reused as necessary to consume all of the \fIarguments\fP.
 If the \fIformat\fP requires more \fIarguments\fP than are supplied, the
 extra format specifications behave as if a zero value or null string, as
@@ -7468,7 +7243,7 @@ input is not read within \fItimeout\fP seconds.
 This option has no effect if \fBread\fP is not reading input from the
 terminal or a pipe.
 .TP
-.B \-u \fIfd\fP
+.B \-u \fIfd\FP
 Read input from file descriptor \fIfd\fP.
 .PD
 .PP
@@ -7537,10 +7312,7 @@ before execution resumes after the function or script.
 .TP
 \fBset\fP [\fB\-\-abefhkmnptuvxBCHP\fP] [\fB\-o\fP \fIoption\fP] [\fIarg\fP ...]
 Without options, the name and value of each shell variable are displayed
-in a format that can be reused as input
-for setting or resetting the currently-set variables.
-Read-only variables cannot be reset.
-In \fIposix mode\fP, only shell variables are listed.
+in a format that can be reused as input.
 The output is sorted according to the current locale.
 When options are specified, they set or unset shell attributes.
 Any arguments remaining after the options are processed are treated
@@ -7554,8 +7326,8 @@ Options, if specified, have the following meanings:
 .PD 0
 .TP 8
 .B \-a
-Automatically mark variables and functions which are modified or
-created for export to the environment of subsequent commands.
+Automatically mark variables and functions which are modified or created
+for export to the environment of subsequent commands.
 .TP 8
 .B \-b
 Report the status of terminated background jobs
@@ -7703,12 +7475,6 @@ Same as
 Same as
 .BR \-P .
 .TP 8
-.B pipefail
-If set, the return value of a pipeline is the value of the last
-(rightmost) command to exit with a non-zero status, or zero if all
-commands in the pipeline exit successfully.
-This option is disabled by default.
-.TP 8
 .B posix
 Change the behavior of
 .B bash
@@ -7827,11 +7593,9 @@ follows the logical chain of directories when performing commands
 which change the current directory.
 .TP 8
 .B \-T
-If set, any traps on \fBDEBUG\fP and \fBRETURN\fP are inherited by shell
-functions, command substitutions, and commands executed in a
-subshell environment.
-The \fBDEBUG\fP and \fBRETURN\fP traps are normally not inherited
-in such cases.
+If set, any trap on \fBDEBUG\fP is inherited by shell functions, command
+substitutions, and commands executed in a subshell environment.
+The \fBDEBUG\fP trap is normally not inherited in such cases.
 .TP 8
 .B \-\-
 If no arguments follow this option, then the positional parameters are
@@ -8011,20 +7775,6 @@ If the command run by the \fBDEBUG\fP trap returns a value of 2, and the
 shell is executing in a subroutine (a shell function or a shell script
 executed by the \fB.\fP or \fBsource\fP builtins), a call to
 \fBreturn\fP is simulated.
-.TP
-.B 4.
-\fBBASH_ARGC\fP and \fBBASH_ARGV\fP are updated as described in their
-descriptions above.
-.TP
-.B 5.
-Function tracing is enabled:  command substitution, shell functions, and
-subshells invoked with \fB(\fP \fIcommand\fP \fB)\fP inherit the
-\fBDEBUG\fP and \fBRETURN\fP traps.
-.TP
-.B 6.
-Error tracing is enabled:  command substitution, shell functions, and
-subshells invoked with \fB(\fP \fIcommand\fP \fB)\fP inherit the
-\fBERROR\fP trap.
 .RE
 .TP 8
 .B extglob
@@ -8036,24 +7786,6 @@ If set, \fB$\fP'\fIstring\fP' 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
-.B failglob
-If set, patterns which fail to match filenames during pathname expansion
-result in an expansion error.
-.TP 8
-.B force_fignore
-If set, the suffixes specified by the \fBFIGNORE\fP shell variable
-cause words to be ignored when performing word completion even if
-the ignored words are the only possible completions.
-See
-.SM
-\fBSHELL VARIABLES\fP
-above for a description of \fBFIGNORE\fP.
-This option is enabled by default.
-.TP 8
-.B gnu_errfmt
-If set, shell error messages are written in the standard GNU error
-message format.
-.TP 8
 .B histappend
 If set, the history list is appended to the file named by the value
 of the
@@ -8134,12 +7866,6 @@ expansion (see
 .B Pathname Expansion
 above).
 .TP 8
-.B nocasematch
-If set,
-.B bash
-matches patterns in a case\-insensitive fashion when performing matching
-while executing \fBcase\fP or \fB[[\fP conditional commands.
-.TP 8
 .B nullglob
 If set,
 .B bash
@@ -8155,9 +7881,8 @@ If set, the programmable completion facilities (see
 This option is enabled by default.
 .TP 8
 .B promptvars
-If set, prompt strings undergo
-parameter expansion, command substitution, arithmetic
-expansion, and quote removal after being expanded as described in
+If set, prompt strings undergo variable and parameter expansion after
+being expanded as described in
 .SM
 .B PROMPTING
 above.  This option is enabled by default.
@@ -8213,8 +7938,6 @@ Each operator and operand must be a separate argument.
 Expressions are composed of the primaries described above under
 .SM
 .BR "CONDITIONAL EXPRESSIONS" .
-\fBtest\fP does not accept any options, nor does it accept and ignore
-an argument of \fB\-\-\fP as signifying the end of options.
 .if t .sp 0.5
 .if n .sp 1
 Expressions may be combined using the following operators, listed
@@ -8301,7 +8024,7 @@ using the rules listed above.
 Print the accumulated user and system times for the shell and
 for processes run from the shell.  The return status is 0.
 .TP
-\fBtrap\fP [\fB\-lp\fP] [[\fIarg\fP] \fIsigspec\fP ...]
+\fBtrap\fP [\fB\-lp\fP] [\fIarg\fP] [\fIsigspec\fP ...]
 The command
 .I arg
 is to be read and executed when the shell receives
@@ -8309,10 +8032,10 @@ signal(s)
 .IR sigspec .
 If
 .I arg
-is absent (and there is a single \fIsigspec\fP) or
+is absent or
 .BR \- ,
-each specified signal is
-reset to its original disposition (the value it had
+all specified signals are
+reset to their original values (the values they had
 upon entrance to the shell).
 If 
 .I arg
@@ -8330,7 +8053,7 @@ If no arguments are supplied or if only
 .B \-p
 is given,
 .B trap
-prints the list of commands associated with each signal.
+prints the list of commands associated with each signal number.
 The
 .B \-l
 option causes the shell to print a list of signal names and
@@ -8339,7 +8062,6 @@ Each
 .I sigspec
 is either
 a signal name defined in <\fIsignal.h\fP>, or a signal number.
-Signal names are case insensitive and the SIG prefix is optional.
 If a
 .I sigspec
 is
@@ -8361,7 +8083,7 @@ command, and before the first command executes in a shell function (see
 .SM
 .B SHELL GRAMMAR
 above).
-Refer to the description of the \fBextdebug\fP option to the
+Refer to the description of the \fBextglob\fP option to the
 \fBshopt\fP builtin for details of its effect on the \fBDEBUG\fP trap.
 If a
 .I sigspec
@@ -8370,8 +8092,7 @@ is
 .BR ERR ,
 the command
 .I arg
-is executed whenever a simple command has a non\-zero exit status,
-subject to the following conditions.
+is executed whenever a simple command has a non\-zero exit status.
 The
 .SM
 .B ERR
@@ -8390,7 +8111,6 @@ or
 list, or if the command's return value is
 being inverted via
 .BR ! .
-These are the same conditions obeyed by the \fBerrexit\fP option.
 If a
 .I sigspec
 is
@@ -8485,7 +8205,7 @@ option suppresses shell function lookup, as with the \fBcommand\fP builtin.
 returns true if any of the arguments are found, false if
 none are found.
 .TP
-\fBulimit\fP [\fB\-SHacdefilmnpqrstuvx\fP [\fIlimit\fP]]
+\fBulimit\fP [\fB\-SHacdflmnpstuv\fP [\fIlimit\fP]]
 Provides control over the resources available to the shell and to
 processes started by it, on systems that allow such control.
 The \fB\-H\fP and \fB\-S\fP options specify that the hard or soft limit is
@@ -8521,15 +8241,9 @@ The maximum size of core files created
 .B \-d
 The maximum size of a process's data segment
 .TP
-.B \-e
-The maximum scheduling priority ("nice")
-.TP
 .B \-f
 The maximum size of files created by the shell
 .TP
-.B \-i
-The maximum number of pending signals
-.TP
 .B \-l
 The maximum size that may be locked into memory
 .TP
@@ -8543,12 +8257,6 @@ allow this value to be set)
 .B \-p
 The pipe size in 512-byte blocks (this may not be set)
 .TP
-.B \-q
-The maximum number of bytes in POSIX message queues
-.TP
-.B \-r
-The maximum real-time scheduling priority
-.TP
 .B \-s
 The maximum stack size
 .TP
@@ -8560,9 +8268,6 @@ The maximum number of processes available to a single user
 .TP
 .B \-v
 The maximum amount of virtual memory available to the shell
-.TP
-.B \-x
-The maximum number of file locks
 .PD
 .PP
 If
@@ -8631,7 +8336,8 @@ refers to a shell variable.
 Read-only variables may not be unset.
 If
 .B \-f
-is specified, each
+is specifed, 
+each
 .I name
 refers to a shell function, and the function definition
 is removed.
@@ -8658,9 +8364,9 @@ subsequently reset.  The exit status is true unless a
 .I name
 is readonly.
 .TP
-\fBwait\fP [\fIn ...\fP]
-Wait for each specified process and return its termination status.
-Each
+\fBwait\fP [\fIn\fP]
+Wait for the specified process and return its termination
+status.
 .I n
 may be a process
 ID or a job specification; if a job spec is given, all processes
@@ -8747,13 +8453,10 @@ turning off restricted mode with
 .PP
 These restrictions are enforced after any startup files are read.
 .PP
-.ie \n(zY=1 When a command that is found to be a shell script is executed,
-.el \{ When a command that is found to be a shell script is executed
-(see
+When a command that is found to be a shell script is executed (see
 .SM
 .B "COMMAND EXECUTION"
 above),
-\}
 .B rbash
 turns off any restrictions in the shell spawned to execute the
 script.
@@ -8804,7 +8507,7 @@ bfox@gnu.org
 .PP
 Chet Ramey, Case Western Reserve University
 .br
-chet@po.cwru.edu
+chet@po.CWRU.Edu
 .SH BUG REPORTS
 If you find a bug in
 .B bash,
@@ -8845,7 +8548,7 @@ it provides for filing a bug report.
 .PP
 Comments and bug reports concerning
 this manual page should be directed to
-.IR chet@po.cwru.edu .
+.IR chet@po.CWRU.Edu .
 .SH BUGS
 .PP
 It's too big and too slow.
@@ -8873,9 +8576,7 @@ a unit.
 .PP
 Commands inside of \fB$(\fP...\fB)\fP command substitution are not
 parsed until substitution is attempted.  This will delay error
-reporting until some time after the command is entered.  For example,
-unmatched parentheses, even inside shell comments, will result in
-error messages while the construct is being read.
+reporting until some time after the command is entered.
 .PP
 Array variables may not (yet) be exported.
 .zZ
index 84065f2b3cb37e1ea9ede4bcfd3d8eaa84209cbd..e0843028887d5eb25c26cc65aff73752b453dcca 100644 (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
index de2cfcc3f57ed6b8ead8f3eb19af961320f97991..6682cc1aa4186be31d829ab15e836cfa62f957b1 100644 (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.
index 93d56c81e67ff7d43a23cf7b57d685c504d5f5eb..de2cfcc3f57ed6b8ead8f3eb19af961320f97991 100644 (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
index 6ee00d428381b096953edf1964ca31cc1d0d3e8a..d1323d0be00ae7cf026e28c07f62a8b945fd619f 100644 (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
index ab97188cd25e11cc4fe54e925aa721d09c1882a5..6ee00d428381b096953edf1964ca31cc1d0d3e8a 100644 (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
index b7a6e7c8af5bd09bb5d810bdfbab50a235094c12..0f099bc19a02b613a4f0a771c0ba6a34a3331c5f 100644 (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
diff --git a/jobs.c b/jobs.c
index 4abc117d05a2513cb3691d39a3c17c8155729d93..3aac6130b02e66e2b4237326c14dc57c515f663d 100644 (file)
--- a/jobs.c
+++ b/jobs.c
@@ -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;
+
+  if (jobs != nlist)
+    {
+      free (jobs);
+      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
diff --git a/jobs.c.save1 b/jobs.c.save1
new file mode 100644 (file)
index 0000000..6c85f24
--- /dev/null
@@ -0,0 +1,4053 @@
+/* The thing that makes children, remembers them, and contains wait loops. */
+
+/* This file works with both POSIX and BSD systems.  It implements job
+   control. */
+
+/* Copyright (C) 1989-2006 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   Bash is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 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"
+#include "trap.h"
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include "posixtime.h"
+
+#if defined (HAVE_SYS_RESOURCE_H) && defined (HAVE_WAIT3) && !defined (_POSIX_VERSION) && !defined (RLIMTYPE)
+#  include <sys/resource.h>
+#endif /* !_POSIX_VERSION && HAVE_SYS_RESOURCE_H && HAVE_WAIT3 && !RLIMTYPE */
+
+#if defined (HAVE_SYS_FILE_H)
+#  include <sys/file.h>
+#endif
+
+#include "filecntl.h"
+#include <sys/ioctl.h>
+#include <sys/param.h>
+
+#if defined (BUFFERED_INPUT)
+#  include "input.h"
+#endif
+
+/* Need to include this up here for *_TTY_DRIVER definitions. */
+#include "shtty.h"
+
+/* Define this if your output is getting swallowed.  It's a no-op on
+   machines with the termio or termios tty drivers. */
+/* #define DRAIN_OUTPUT */
+
+/* For the TIOCGPGRP and TIOCSPGRP ioctl parameters on HP-UX */
+#if defined (hpux) && !defined (TERMIOS_TTY_DRIVER)
+#  include <bsdtty.h>
+#endif /* hpux && !TERMIOS_TTY_DRIVER */
+
+#include "bashansi.h"
+#include "bashintl.h"
+#include "shell.h"
+#include "jobs.h"
+#include "flags.h"
+
+#include "builtins/builtext.h"
+#include "builtins/common.h"
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+#define DEFAULT_CHILD_MAX 32
+#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
+   waitpid() function. */
+
+#if defined (ultrix) && defined (mips) && defined (_POSIX_VERSION)
+#  define WAITPID(pid, statusp, options) \
+       wait3 ((union wait *)statusp, options, (struct rusage *)0)
+#else
+#  if defined (_POSIX_VERSION) || defined (HAVE_WAITPID)
+#    define WAITPID(pid, statusp, options) \
+       waitpid ((pid_t)pid, statusp, options)
+#  else
+#    if defined (HAVE_WAIT3)
+#      define WAITPID(pid, statusp, options) \
+       wait3 (statusp, options, (struct rusage *)0)
+#    else
+#      define WAITPID(pid, statusp, options) \
+       wait3 (statusp, options, (int *)0)
+#    endif /* HAVE_WAIT3 */
+#  endif /* !_POSIX_VERSION && !HAVE_WAITPID*/
+#endif /* !(Ultrix && mips && _POSIX_VERSION) */
+
+/* getpgrp () varies between systems.  Even systems that claim to be
+   Posix.1 compatible lie sometimes (Ultrix, SunOS4, apollo). */
+#if defined (GETPGRP_VOID)
+#  define getpgid(p) getpgrp ()
+#else
+#  define getpgid(p) getpgrp (p)
+#endif /* !GETPGRP_VOID */
+
+/* If the system needs it, REINSTALL_SIGCHLD_HANDLER will reinstall the
+   handler for SIGCHLD. */
+#if defined (MUST_REINSTALL_SIGHANDLERS)
+#  define REINSTALL_SIGCHLD_HANDLER signal (SIGCHLD, sigchld_handler)
+#else
+#  define REINSTALL_SIGCHLD_HANDLER
+#endif /* !MUST_REINSTALL_SIGHANDLERS */
+
+/* Some systems let waitpid(2) tell callers about stopped children. */
+#if !defined (WCONTINUED) || defined (WCONTINUED_BROKEN)
+#  undef WCONTINUED
+#  define WCONTINUED 0
+#endif
+#if !defined (WIFCONTINUED)
+#  define WIFCONTINUED(s)      (0)
+#endif
+
+/* The number of additional slots to allocate when we run out. */
+#define JOB_SLOTS 8
+
+typedef int sh_job_map_func_t __P((JOB *, int, int, int));
+
+/* Variables used here but defined in other files. */
+extern int subshell_environment, line_number;
+extern int posixly_correct, shell_level;
+extern int interrupt_immediately;
+extern int last_command_exit_value, last_command_exit_signal;
+extern int loop_level, breaking;
+extern int sourcelevel;
+extern sh_builtin_func_t *this_shell_builtin;
+extern char *shell_name, *this_command_name;
+extern sigset_t top_level_mask;
+extern procenv_t wait_intr_buf;
+extern int wait_signal_received;
+extern WORD_LIST *subst_assign_varlist;
+
+static struct jobstats zerojs = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB, 0, 0 };
+struct jobstats js = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB, 0, 0 };
+
+struct bgpids bgpids = { 0, 0, 0 };
+
+/* The array of known jobs. */
+JOB **jobs = (JOB **)NULL;
+
+#if 0
+/* The number of slots currently allocated to JOBS. */
+int job_slots = 0;
+#endif
+
+/* The controlling tty for this shell. */
+int shell_tty = -1;
+
+/* The shell's process group. */
+pid_t shell_pgrp = NO_PID;
+
+/* The terminal's process group. */
+pid_t terminal_pgrp = NO_PID;
+
+/* The process group of the shell's parent. */
+pid_t original_pgrp = NO_PID;
+
+/* The process group of the pipeline currently being made. */
+pid_t pipeline_pgrp = (pid_t)0;
+
+#if defined (PGRP_PIPE)
+/* Pipes which each shell uses to communicate with the process group leader
+   until all of the processes in a pipeline have been started.  Then the
+   process leader is allowed to continue. */
+int pgrp_pipe[2] = { -1, -1 };
+#endif
+
+#if 0
+/* The job which is current; i.e. the one that `%+' stands for. */
+int current_job = NO_JOB;
+
+/* The previous job; i.e. the one that `%-' stands for. */
+int previous_job = NO_JOB;
+#endif
+
+/* Last child made by the shell.  */
+pid_t last_made_pid = NO_PID;
+
+/* Pid of the last asynchronous child. */
+pid_t last_asynchronous_pid = NO_PID;
+
+/* The pipeline currently being built. */
+PROCESS *the_pipeline = (PROCESS *)NULL;
+
+/* If this is non-zero, do job control. */
+int job_control = 1;
+
+/* Call this when you start making children. */
+int already_making_children = 0;
+
+/* If this is non-zero, $LINES and $COLUMNS are reset after every process
+   exits from get_tty_state(). */
+int check_window_size;
+
+/* Functions local to this file. */
+
+static void run_sigchld_trap __P((int));
+
+static sighandler wait_sigint_handler __P((int));
+static sighandler sigchld_handler __P((int));
+static sighandler sigcont_sighandler __P((int));
+static sighandler sigstop_sighandler __P((int));
+
+static int waitchld __P((pid_t, int));
+
+static PROCESS *find_pipeline __P((pid_t, int, int *));
+static PROCESS *find_process __P((pid_t, int, int *));
+
+static char *current_working_directory __P((void));
+static char *job_working_directory __P((void));
+static char *j_strsignal __P((int));
+static char *printable_job_status __P((int, PROCESS *, int));
+
+static PROCESS *find_last_proc __P((int, int));
+static pid_t find_last_pid __P((int, int));
+
+static int set_new_line_discipline __P((int));
+static int map_over_jobs __P((sh_job_map_func_t *, int, int));
+static int job_last_stopped __P((int));
+static int job_last_running __P((int));
+static int most_recent_job_in_state __P((int, JOB_STATE));
+static int find_job __P((pid_t, int, PROCESS **));
+static int print_job __P((JOB *, int, int, int));
+static int process_exit_status __P((WAIT));
+static int process_exit_signal __P((WAIT));
+static int job_exit_status __P((int));
+static int job_exit_signal __P((int));
+static int set_job_status_and_cleanup __P((int));
+
+static WAIT raw_job_exit_status __P((int));
+
+static void notify_of_job_status __P((void));
+static void reset_job_indices __P((void));
+static void cleanup_dead_jobs __P((void));
+static int processes_in_job __P((int));
+static void realloc_jobs_list __P((void));
+static int compact_jobs_list __P((int));
+static int discard_pipeline __P((PROCESS *));
+static void add_process __P((char *, pid_t));
+static void print_pipeline __P((PROCESS *, int, int, FILE *));
+static void pretty_print_job __P((int, int, FILE *));
+static void set_current_job __P((int));
+static void reset_current __P((void));
+static void set_job_running __P((int));
+static void setjstatus __P((int));
+static void mark_all_jobs_as_dead __P((void));
+static void mark_dead_jobs_as_notified __P((int));
+static void restore_sigint_handler __P((void));
+#if defined (PGRP_PIPE)
+static void pipe_read __P((int *));
+static void pipe_close __P((int *));
+#endif
+
+static struct pidstat *bgp_alloc __P((pid_t, int));
+static struct pidstat *bgp_add __P((pid_t, int));
+static int bgp_delete __P((pid_t));
+static void bgp_clear __P((void));
+static int bgp_search __P((pid_t));
+static void bgp_prune __P((void));
+
+#if defined (ARRAY_VARS)
+static int *pstatuses;         /* list of pipeline statuses */
+static int statsize;
+#endif
+
+/* Used to synchronize between wait_for and other functions and the SIGCHLD
+   signal handler. */
+static int sigchld;
+static int queue_sigchld;
+
+#define QUEUE_SIGCHLD(os)      (os) = sigchld, queue_sigchld++
+
+#define UNQUEUE_SIGCHLD(os) \
+       do { \
+         queue_sigchld--; \
+         if (queue_sigchld == 0 && os != sigchld) \
+           waitchld (-1, 0); \
+       } while (0)
+
+static SigHandler *old_tstp, *old_ttou, *old_ttin;
+static SigHandler *old_cont = (SigHandler *)SIG_DFL;
+
+/* A place to temporarily save the current pipeline. */
+static PROCESS *saved_pipeline;
+static int saved_already_making_children;
+
+/* Set this to non-zero whenever you don't want the jobs list to change at
+   all: no jobs deleted and no status change notifications.  This is used,
+   for example, when executing SIGCHLD traps, which may run arbitrary
+   commands. */
+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
+   library functions and system calls. */
+#define setpgid(pid, pgrp)     setpgrp (pid, pgrp)
+#define tcsetpgrp(fd, pgrp)    ioctl ((fd), TIOCSPGRP, &(pgrp))
+
+pid_t
+tcgetpgrp (fd)
+     int fd;
+{
+  pid_t pgrp;
+
+  /* ioctl will handle setting errno correctly. */
+  if (ioctl (fd, TIOCGPGRP, &pgrp) < 0)
+    return (-1);
+  return (pgrp);
+}
+
+#endif /* !_POSIX_VERSION */
+
+/* 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
+   job_working_directory, this does not call malloc (), nor do any
+   of the functions it calls.  This is so that it can safely be called
+   from a signal handler. */
+static char *
+current_working_directory ()
+{
+  char *dir;
+  static char d[PATH_MAX];
+
+  dir = get_string_value ("PWD");
+
+  if (dir == 0 && the_current_working_directory && no_symbolic_links)
+    dir = the_current_working_directory;
+
+  if (dir == 0)
+    {
+      dir = getcwd (d, sizeof(d));
+      if (dir)
+       dir = d;
+    }
+
+  return (dir == 0) ? "<unknown>" : dir;
+}
+
+/* Return the working directory for the current process. */
+static char *
+job_working_directory ()
+{
+  char *dir;
+
+  dir = get_string_value ("PWD");
+  if (dir)
+    return (savestring (dir));
+
+  dir = get_working_directory ("job-working-directory");
+  if (dir)
+    return (dir);
+
+  return (savestring ("<unknown>"));
+}
+
+void
+making_children ()
+{
+  if (already_making_children)
+    return;
+
+  already_making_children = 1;
+  start_pipeline ();
+}
+
+void
+stop_making_children ()
+{
+  already_making_children = 0;
+}
+
+void
+cleanup_the_pipeline ()
+{
+  PROCESS *disposer;
+  sigset_t set, oset;
+
+  BLOCK_CHILD (set, oset);
+  disposer = the_pipeline;
+  the_pipeline = (PROCESS *)NULL;
+  UNBLOCK_CHILD (oset);
+
+  if (disposer)
+    discard_pipeline (disposer);
+}
+
+void
+save_pipeline (clear)
+     int clear;
+{
+  saved_pipeline = the_pipeline;
+  if (clear)
+    the_pipeline = (PROCESS *)NULL;
+  saved_already_making_children = already_making_children;
+}
+
+void
+restore_pipeline (discard)
+     int discard;
+{
+  PROCESS *old_pipeline;
+
+  old_pipeline = the_pipeline;
+  the_pipeline = saved_pipeline;
+  already_making_children = saved_already_making_children;
+  if (discard)
+    discard_pipeline (old_pipeline);
+}
+
+/* Start building a pipeline.  */
+void
+start_pipeline ()
+{
+  if (the_pipeline)
+    {
+      cleanup_the_pipeline ();
+      pipeline_pgrp = 0;
+#if defined (PGRP_PIPE)
+      pipe_close (pgrp_pipe);
+#endif
+    }
+
+#if defined (PGRP_PIPE)
+  if (job_control)
+    {
+      if (pipe (pgrp_pipe) == -1)
+       sys_error ("start_pipeline: pgrp pipe");
+    }
+#endif
+}
+
+/* Stop building a pipeline.  Install the process list in the job array.
+   This returns the index of the newly installed job.
+   DEFERRED is a command structure to be executed upon satisfactory
+   execution exit of this pipeline. */
+int
+stop_pipeline (async, deferred)
+     int async;
+     COMMAND *deferred;
+{
+  register int i, j;
+  JOB *newjob;
+  sigset_t set, oset;
+
+  BLOCK_CHILD (set, oset);
+
+#if defined (PGRP_PIPE)
+  /* The parent closes the process group synchronization pipe. */
+  pipe_close (pgrp_pipe);
+#endif
+
+  cleanup_dead_jobs ();
+
+  if (js.j_jobslots == 0)
+    {
+      js.j_jobslots = JOB_SLOTS;
+      jobs = (JOB **)xmalloc (js.j_jobslots * sizeof (JOB *));
+
+      /* Now blank out these new entries. */
+      for (i = 0; i < js.j_jobslots; i++)
+       jobs[i] = (JOB *)NULL;
+
+      js.j_firstj = js.j_lastj = js.j_njobs = 0;
+    }
+
+  /* Scan from the last slot backward, looking for the next free one. */
+  /* XXX - revisit this interactive assumption */
+  /* XXX - this way for now */
+  if (interactive)
+    {
+      for (i = js.j_jobslots; i; i--)
+       if (jobs[i - 1])
+         break;
+    }
+  else
+    {
+#if 0
+      /* This wraps around, but makes it inconvenient to extend the array */
+      for (i = js.j_lastj+1; i != js.j_lastj; i++)
+       {
+         if (i >= js.j_jobslots)
+           i = 0;
+         if (jobs[i] == 0)
+           break;
+       }       
+      if (i == js.j_lastj)
+        i = js.j_jobslots;
+#else
+      /* This doesn't wrap around yet. */
+      for (i = js.j_lastj ? js.j_lastj + 1 : js.j_lastj; i < js.j_jobslots; i++)
+       if (jobs[i] == 0)
+         break;
+#endif
+    }
+
+  /* Do we need more room? */
+
+  /* First try compaction */
+  if ((interactive_shell == 0 || subshell_environment) && i == js.j_jobslots && js.j_jobslots >= MAX_JOBS_IN_ARRAY)
+    i = compact_jobs_list (0);
+
+  /* If we can't compact, reallocate */
+  if (i == js.j_jobslots)
+    {
+      js.j_jobslots += JOB_SLOTS;
+      jobs = (JOB **)xrealloc (jobs, (js.j_jobslots * sizeof (JOB *)));
+
+      for (j = i; j < js.j_jobslots; j++)
+       jobs[j] = (JOB *)NULL;
+    }
+
+  /* Add the current pipeline to the job list. */
+  if (the_pipeline)
+    {
+      register PROCESS *p;
+      int any_running, any_stopped, n;
+
+      newjob = (JOB *)xmalloc (sizeof (JOB));
+
+      for (n = 1, p = the_pipeline; p->next != the_pipeline; n++, p = p->next)
+       ;
+      p->next = (PROCESS *)NULL;
+      newjob->pipe = REVERSE_LIST (the_pipeline, PROCESS *);
+      for (p = newjob->pipe; p->next; p = p->next)
+       ;
+      p->next = newjob->pipe;
+
+      the_pipeline = (PROCESS *)NULL;
+      newjob->pgrp = pipeline_pgrp;
+      pipeline_pgrp = 0;
+
+      newjob->flags = 0;
+
+      /* Flag to see if in another pgrp. */
+      if (job_control)
+       newjob->flags |= J_JOBCONTROL;
+
+      /* Set the state of this pipeline. */
+      p = newjob->pipe;
+      any_running = any_stopped = 0;
+      do
+       {
+         any_running |= PRUNNING (p);
+         any_stopped |= PSTOPPED (p);
+         p = p->next;
+       }
+      while (p != newjob->pipe);
+
+      newjob->state = any_running ? JRUNNING : (any_stopped ? JSTOPPED : JDEAD);
+      newjob->wd = job_working_directory ();
+      newjob->deferred = deferred;
+
+      newjob->j_cleanup = (sh_vptrfunc_t *)NULL;
+      newjob->cleanarg = (PTR_T) NULL;
+
+      jobs[i] = newjob;
+      if (newjob->state == JDEAD && (newjob->flags & J_FOREGROUND))
+       setjstatus (i);
+      if (newjob->state == JDEAD)
+       {
+         js.c_reaped += n;     /* wouldn't have been done since this was not part of a job */
+         js.j_ndead++;
+       }
+      js.c_injobs += n;
+
+      js.j_lastj = i;
+      js.j_njobs++;
+    }
+  else
+    newjob = (JOB *)NULL;
+
+  if (newjob)
+    js.j_lastmade = newjob;
+
+  if (async)
+    {
+      if (newjob)
+       {
+         newjob->flags &= ~J_FOREGROUND;
+         newjob->flags |= J_ASYNC;
+         js.j_lastasync = newjob;
+       }
+      reset_current ();
+    }
+  else
+    {
+      if (newjob)
+       {
+         newjob->flags |= J_FOREGROUND;
+         /*
+          *            !!!!! NOTE !!!!!  (chet@ins.cwru.edu)
+          *
+          * The currently-accepted job control wisdom says to set the
+          * terminal's process group n+1 times in an n-step pipeline:
+          * once in the parent and once in each child.  This is where
+          * the parent gives it away.
+          *
+          */
+         if (job_control && newjob->pgrp)
+           give_terminal_to (newjob->pgrp, 0);
+       }
+    }
+
+  stop_making_children ();
+  UNBLOCK_CHILD (oset);
+  return (js.j_current);
+}
+
+/* Functions to manage the list of exited background pids whose status has
+   been saved. */
+
+static struct pidstat *
+bgp_alloc (pid, status)
+     pid_t pid;
+     int status;
+{
+  struct pidstat *ps;
+
+  ps = (struct pidstat *)xmalloc (sizeof (struct pidstat));
+  ps->pid = pid;
+  ps->status = status;
+  ps->next = (struct pidstat *)0;
+  return ps;
+}
+
+static struct pidstat *
+bgp_add (pid, status)
+     pid_t pid;
+     int status;
+{
+  struct pidstat *ps;
+
+  ps = bgp_alloc (pid, status);
+
+  if (bgpids.list == 0)
+    {
+      bgpids.list = bgpids.end = ps;
+      bgpids.npid = 0;                 /* just to make sure */
+    }
+  else
+    {
+      bgpids.end->next = ps;
+      bgpids.end = ps;
+    }
+  bgpids.npid++;
+
+  if (bgpids.npid > js.c_childmax)
+    bgp_prune ();
+
+  return ps;
+}
+
+static int
+bgp_delete (pid)
+     pid_t pid;
+{
+  struct pidstat *prev, *p;
+
+  for (prev = p = bgpids.list; p; prev = p, p = p->next)
+    if (p->pid == pid)
+      {
+        prev->next = p->next;  /* remove from list */
+        break;
+      }
+
+  if (p == 0)
+    return 0;          /* not found */
+
+#if defined (DEBUG)
+  itrace("bgp_delete: deleting %d", pid);
+#endif
+
+  /* Housekeeping in the border cases. */
+  if (p == bgpids.list)
+    bgpids.list = bgpids.list->next;
+  else if (p == bgpids.end)
+    bgpids.end = prev;
+
+  bgpids.npid--;
+  if (bgpids.npid == 0)
+    bgpids.list = bgpids.end = 0;
+  else if (bgpids.npid == 1)
+    bgpids.end = bgpids.list;          /* just to make sure */
+
+  free (p);
+  return 1;
+}
+
+/* Clear out the list of saved statuses */
+static void
+bgp_clear ()
+{
+  struct pidstat *ps, *p;
+
+  for (ps = bgpids.list; ps; )
+    {
+      p = ps;
+      ps = ps->next;
+      free (p);
+    }
+  bgpids.list = bgpids.end = 0;
+  bgpids.npid = 0;
+}
+
+/* Search for PID in the list of saved background pids; return its status if
+   found.  If not found, return -1. */
+static int
+bgp_search (pid)
+     pid_t pid;
+{
+  struct pidstat *ps;
+
+  for (ps = bgpids.list ; ps; ps = ps->next)
+    if (ps->pid == pid)
+      return ps->status;
+  return -1;
+}
+
+static void
+bgp_prune ()
+{
+  struct pidstat *ps, *p;
+
+  while (bgpids.npid > js.c_childmax)
+    {
+      ps = bgpids.list;
+      bgpids.list = bgpids.list->next;
+      free (ps);
+      bgpids.npid--;
+    }
+}
+    
+/* Reset the values of js.j_lastj and js.j_firstj after one or both have
+   been deleted.  The caller should check whether js.j_njobs is 0 before
+   calling this.  This wraps around, but the rest of the code does not.  At
+   this point, it should not matter. */
+static void
+reset_job_indices ()
+{
+  int old;
+
+  if (jobs[js.j_firstj] == 0)
+    {
+      old = js.j_firstj++;
+      while (js.j_firstj != old)
+       {
+         if (js.j_firstj >= js.j_jobslots)
+           js.j_firstj = 0;
+         if (jobs[js.j_firstj])
+           break;
+         js.j_firstj++;
+       }
+      if (js.j_firstj == old)
+        js.j_firstj = js.j_lastj = js.j_njobs = 0;
+    }
+  if (jobs[js.j_lastj] == 0)
+    {
+      old = js.j_lastj--;
+      while (js.j_lastj != old)
+       {
+         if (js.j_lastj < 0)
+           js.j_lastj = js.j_jobslots - 1;
+         if (jobs[js.j_lastj])
+           break;
+         js.j_lastj--;
+       }
+      if (js.j_lastj == old)
+        js.j_firstj = js.j_lastj = js.j_njobs = 0;
+    }
+}
+      
+/* Delete all DEAD jobs that the user had received notification about. */
+static void
+cleanup_dead_jobs ()
+{
+  register int i;
+  int os;
+
+  if (js.j_jobslots == 0 || jobs_list_frozen)
+    return;
+
+  QUEUE_SIGCHLD(os);
+
+  /* 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))
+       delete_job (i, 0);
+    }
+  UNQUEUE_SIGCHLD(os);
+}
+
+static int
+processes_in_job (job)
+{
+  int nproc;
+  register PROCESS *p;
+
+  nproc = 0;
+  p = jobs[job]->pipe;
+  do
+    {
+      p = p->next;
+      nproc++;
+    }
+  while (p != jobs[job]->pipe);
+
+  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)
+    itrace ("delete_old_job: found pid %d in job %d with state %d", pid, job, jobs[job]->state);
+}
+
+/* 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. */
+static void
+realloc_jobs_list ()
+{
+  sigset_t set, oset;
+  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;
+  if (i == 0 || i > (JOB_SLOTS >> 1))
+    nsize += JOB_SLOTS;
+
+  BLOCK_CHILD (set, oset);
+  nlist = (js.j_jobslots == nsize) ? jobs : (JOB **) xmalloc (nsize * sizeof (JOB *));
+
+  for (i = j = 0; i < js.j_jobslots; i++)
+    if (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_njobs = j;
+  js.j_jobslots = nsize;
+
+  /* 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);
+}
+
+/* Compact the jobs list by removing dead jobs.  Assumed that we have filled
+   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 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)
+     int flags;
+{
+  if (js.j_jobslots == 0 || jobs_list_frozen)
+    return js.j_jobslots;
+
+  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, dflags)
+     int job_index, dflags;
+{
+  register JOB *temp;
+  PROCESS *proc;
+  int ndel, status;
+  pid_t pid;
+
+  if (js.j_jobslots == 0 || jobs_list_frozen)
+    return;
+
+  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)
+    return;
+  if (job_index == js.j_current || job_index == js.j_previous)
+    reset_current ();
+
+  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)
+    js.j_lastmade = 0;
+  else if (temp == js.j_lastasync)
+    js.j_lastasync = 0;
+
+  free (temp->wd);
+  ndel = discard_pipeline (temp->pipe);
+
+  js.c_injobs -= ndel;
+  if (temp->state == JDEAD)
+    {
+      js.c_reaped -= ndel;
+      js.j_ndead--;
+      if (js.c_reaped < 0)
+       {
+#ifdef DEBUG
+         itrace("delete_job (%d pgrp %d): js.c_reaped (%d) < 0 ndel = %d js.j_ndead = %d", job_index, temp->pgrp, js.c_reaped, ndel, js.j_ndead);
+#endif
+         js.c_reaped = 0;
+       }
+    }
+
+  if (temp->deferred)
+    dispose_command (temp->deferred);
+
+  free (temp);
+
+  js.j_njobs--;
+  if (js.j_njobs == 0)
+    js.j_firstj = js.j_lastj = 0;
+  else if (jobs[js.j_firstj] == 0 || jobs[js.j_lastj] == 0)
+    reset_job_indices ();
+}
+
+/* Must be called with SIGCHLD blocked. */
+void
+nohup_job (job_index)
+     int job_index;
+{
+  register JOB *temp;
+
+  if (js.j_jobslots == 0)
+    return;
+
+  if (temp = jobs[job_index])
+    temp->flags |= J_NOHUP;
+}
+
+/* Get rid of the data structure associated with a process chain. */
+static int
+discard_pipeline (chain)
+     register PROCESS *chain;
+{
+  register PROCESS *this, *next;
+  int n;
+
+  this = chain;
+  n = 0;
+  do
+    {
+      next = this->next;
+      FREE (this->command);
+      free (this);
+      n++;
+      this = next;
+    }
+  while (this != chain);
+
+  return n;
+}
+
+/* Add this process to the chain being built in the_pipeline.
+   NAME is the command string that will be exec'ed later.
+   PID is the process id of the child. */
+static void
+add_process (name, pid)
+     char *name;
+     pid_t pid;
+{
+  PROCESS *t, *p;
+
+#if defined (RECYCLES_PIDS)
+  int j;
+  p = find_process (pid, 0, &j);
+  if (p)
+    {
+#  ifdef DEBUG
+      if (j == NO_JOB)
+       internal_warning ("add_process: process %5ld (%s) in the_pipeline", (long)p->pid, p->command);
+#  endif
+      if (PALIVE (p))
+        internal_warning ("add_process: pid %5ld (%s) marked as still alive", (long)p->pid, p->command);
+      p->running = PS_RECYCLED;                /* mark as recycled */
+    }
+#endif
+
+  t = (PROCESS *)xmalloc (sizeof (PROCESS));
+  t->next = the_pipeline;
+  t->pid = pid;
+  WSTATUS (t->status) = 0;
+  t->running = PS_RUNNING;
+  t->command = name;
+  the_pipeline = t;
+
+  if (t->next == 0)
+    t->next = t;
+  else
+    {
+      p = t->next;
+      while (p->next != t->next)
+       p = p->next;
+      p->next = t;
+    }
+}
+
+#if 0
+/* Take the last job and make it the first job.  Must be called with
+   SIGCHLD blocked. */
+int
+rotate_the_pipeline ()
+{
+  PROCESS *p;
+
+  if (the_pipeline->next == the_pipeline)
+    return;
+  for (p = the_pipeline; p->next != the_pipeline; p = p->next)
+    ;
+  the_pipeline = p;
+}
+
+/* Reverse the order of the processes in the_pipeline.  Must be called with
+   SIGCHLD blocked. */
+int
+reverse_the_pipeline ()
+{
+  PROCESS *p, *n;
+
+  if (the_pipeline->next == the_pipeline)
+    return;
+
+  for (p = the_pipeline; p->next != the_pipeline; p = p->next)
+    ;
+  p->next = (PROCESS *)NULL;
+
+  n = REVERSE_LIST (the_pipeline, PROCESS *);
+
+  the_pipeline = n;
+  for (p = the_pipeline; p->next; p = p->next)
+    ;
+  p->next = the_pipeline;
+}
+#endif
+
+/* Map FUNC over the list of jobs.  If FUNC returns non-zero,
+   then it is time to stop mapping, and that is the return value
+   for map_over_jobs.  FUNC is called with a JOB, arg1, arg2,
+   and INDEX. */
+static int
+map_over_jobs (func, arg1, arg2)
+     sh_job_map_func_t *func;
+     int arg1, arg2;
+{
+  register int i;
+  int result;
+  sigset_t set, oset;
+
+  if (js.j_jobslots == 0)
+    return 0;
+
+  BLOCK_CHILD (set, oset);
+
+  /* XXX could use js.j_firstj here */
+  for (i = result = 0; i < js.j_jobslots; i++)
+    {
+#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])
+       {
+         result = (*func)(jobs[i], arg1, arg2, i);
+         if (result)
+           break;
+       }
+    }
+
+  UNBLOCK_CHILD (oset);
+
+  return (result);
+}
+
+/* Cause all the jobs in the current pipeline to exit. */
+void
+terminate_current_pipeline ()
+{
+  if (pipeline_pgrp && pipeline_pgrp != shell_pgrp)
+    {
+      killpg (pipeline_pgrp, SIGTERM);
+      killpg (pipeline_pgrp, SIGCONT);
+    }
+}
+
+/* Cause all stopped jobs to exit. */
+void
+terminate_stopped_jobs ()
+{
+  register int i;
+
+  /* XXX could use js.j_firstj here */
+  for (i = 0; i < js.j_jobslots; i++)
+    {
+      if (jobs[i] && STOPPED (i))
+       {
+         killpg (jobs[i]->pgrp, SIGTERM);
+         killpg (jobs[i]->pgrp, SIGCONT);
+       }
+    }
+}
+
+/* Cause all jobs, running or stopped, to receive a hangup signal.  If
+   a job is marked J_NOHUP, don't send the SIGHUP. */
+void
+hangup_all_jobs ()
+{
+  register int i;
+
+  /* XXX could use js.j_firstj here */
+  for (i = 0; i < js.j_jobslots; i++)
+    {
+      if (jobs[i])
+       {
+         if  ((jobs[i]->flags & J_NOHUP) == 0)
+           killpg (jobs[i]->pgrp, SIGHUP);
+         if (STOPPED (i))
+           killpg (jobs[i]->pgrp, SIGCONT);
+       }
+    }
+}
+
+void
+kill_current_pipeline ()
+{
+  stop_making_children ();
+  start_pipeline ();
+}
+
+/* Return the pipeline that PID belongs to.  Note that the pipeline
+   doesn't have to belong to a job.  Must be called with SIGCHLD blocked.
+   If JOBP is non-null, return the index of the job containing PID.  */
+static PROCESS *
+find_pipeline (pid, alive_only, jobp)
+     pid_t pid;
+     int alive_only;
+     int *jobp;                /* index into jobs list or NO_JOB */
+{
+  int job;
+  PROCESS *p;
+
+  /* See if this process is in the pipeline that we are building. */
+  if (jobp)
+    *jobp = NO_JOB;
+  if (the_pipeline)
+    {
+      p = the_pipeline;
+      do
+       {
+         /* Return it if we found it.  Don't ever return a recycled pid. */
+         if (p->pid == pid && ((alive_only == 0 && PRECYCLED(p) == 0) || PALIVE(p)))
+           return (p);
+
+         p = p->next;
+       }
+      while (p != the_pipeline);
+    }
+
+  job = find_job (pid, alive_only, &p);
+  if (jobp)
+    *jobp = job;
+  return (job == NO_JOB) ? (PROCESS *)NULL : jobs[job]->pipe;
+}
+
+/* Return the PROCESS * describing PID.  If JOBP is non-null return the index
+   into the jobs array of the job containing PID.  Must be called with
+   SIGCHLD blocked. */
+static PROCESS *
+find_process (pid, alive_only, jobp)
+     pid_t pid;
+     int alive_only;
+     int *jobp;                /* index into jobs list or NO_JOB */
+{
+  PROCESS *p;
+
+  p = find_pipeline (pid, alive_only, jobp);
+  while (p && p->pid != pid)
+    p = p->next;
+  return p;
+}
+
+/* Return the job index that PID belongs to, or NO_JOB if it doesn't
+   belong to any job.  Must be called with SIGCHLD blocked. */
+static int
+find_job (pid, alive_only, procp)
+     pid_t pid;
+     int alive_only;
+     PROCESS **procp;
+{
+  register int i;
+  PROCESS *p;
+
+  /* XXX could use js.j_firstj here, and should check js.j_lastj */
+  for (i = 0; i < js.j_jobslots; i++)
+    {
+#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])
+       {
+         p = jobs[i]->pipe;
+
+         do
+           {
+             if (p->pid == pid && ((alive_only == 0 && PRECYCLED(p) == 0) || PALIVE(p)))
+               {
+                 if (procp)
+                   *procp = p;
+                 return (i);
+               }
+
+             p = p->next;
+           }
+         while (p != jobs[i]->pipe);
+       }
+    }
+
+  return (NO_JOB);
+}
+
+/* Find a job given a PID.  If BLOCK is non-zero, block SIGCHLD as
+   required by find_job. */
+int
+get_job_by_pid (pid, block)
+     pid_t pid;
+     int block;
+{
+  int job;
+  sigset_t set, oset;
+
+  if (block)
+    BLOCK_CHILD (set, oset);
+
+  job = find_job (pid, 0, NULL);
+
+  if (block)
+    UNBLOCK_CHILD (oset);
+
+  return job;
+}
+
+/* Print descriptive information about the job with leader pid PID. */
+void
+describe_pid (pid)
+     pid_t pid;
+{
+  int job;
+  sigset_t set, oset;
+
+  BLOCK_CHILD (set, oset);
+
+  job = find_job (pid, 0, NULL);
+
+  if (job != NO_JOB)
+    fprintf (stderr, "[%d] %ld\n", job + 1, (long)pid);
+  else
+    programming_error (_("describe_pid: %ld: no such pid"), (long)pid);
+
+  UNBLOCK_CHILD (oset);
+}
+
+static char *
+j_strsignal (s)
+     int s;
+{
+  char *x;
+
+  x = strsignal (s);
+  if (x == 0)
+    {
+      x = retcode_name_buffer;
+      sprintf (x, "Signal %d", s);
+    }
+  return x;
+}
+
+static char *
+printable_job_status (j, p, format)
+     int j;
+     PROCESS *p;
+     int format;
+{
+  static char *temp;
+  int es;
+
+  temp = "Done";
+
+  if (STOPPED (j) && format == 0)
+    {
+      if (posixly_correct == 0 || p == 0 || (WIFSTOPPED (p->status) == 0))
+       temp = "Stopped";
+      else
+       {
+         temp = retcode_name_buffer;
+         sprintf (temp, "Stopped(%s)", signal_name (WSTOPSIG (p->status)));
+       }
+    }
+  else if (RUNNING (j))
+    temp = "Running";
+  else
+    {
+      if (WIFSTOPPED (p->status))
+       temp = j_strsignal (WSTOPSIG (p->status));
+      else if (WIFSIGNALED (p->status))
+       temp = j_strsignal (WTERMSIG (p->status));
+      else if (WIFEXITED (p->status))
+       {
+         temp = retcode_name_buffer;
+         es = WEXITSTATUS (p->status);
+         if (es == 0)
+           strcpy (temp, "Done");
+         else if (posixly_correct)
+           sprintf (temp, "Done(%d)", es);
+         else
+           sprintf (temp, "Exit %d", es);
+       }
+      else
+       temp = "Unknown status";
+    }
+
+  return temp;
+}
+
+/* This is the way to print out information on a job if you
+   know the index.  FORMAT is:
+
+    JLIST_NORMAL)   [1]+ Running          emacs
+    JLIST_LONG  )   [1]+ 2378 Running      emacs
+    -1   )   [1]+ 2378       emacs
+
+    JLIST_NORMAL)   [1]+ Stopped          ls | more
+    JLIST_LONG  )   [1]+ 2369 Stopped      ls
+                        2367       | more
+    JLIST_PID_ONLY)
+       Just list the pid of the process group leader (really
+       the process group).
+    JLIST_CHANGED_ONLY)
+       Use format JLIST_NORMAL, but list only jobs about which
+       the user has not been notified. */
+
+/* Print status for pipeline P.  If JOB_INDEX is >= 0, it is the index into
+   the JOBS array corresponding to this pipeline.  FORMAT is as described
+   above.  Must be called with SIGCHLD blocked.
+
+   If you're printing a pipeline that's not in the jobs array, like the
+   current pipeline as it's being created, pass -1 for JOB_INDEX */
+static void
+print_pipeline (p, job_index, format, stream)
+     PROCESS *p;
+     int job_index, format;
+     FILE *stream;
+{
+  PROCESS *first, *last, *show;
+  int es, name_padding;
+  char *temp;
+
+  if (p == 0)
+    return;
+
+  first = last = p;
+  while (last->next != first)
+    last = last->next;
+
+  for (;;)
+    {
+      if (p != first)
+       fprintf (stream, format ? "     " : " |");
+
+      if (format != JLIST_STANDARD)
+       fprintf (stream, "%5ld", (long)p->pid);
+
+      fprintf (stream, " ");
+
+      if (format > -1 && job_index >= 0)
+       {
+         show = format ? p : last;
+         temp = printable_job_status (job_index, show, format);
+
+         if (p != first)
+           {
+             if (format)
+               {
+                 if (show->running == first->running &&
+                     WSTATUS (show->status) == WSTATUS (first->status))
+                   temp = "";
+               }
+             else
+               temp = (char *)NULL;
+           }
+
+         if (temp)
+           {
+             fprintf (stream, "%s", temp);
+
+             es = STRLEN (temp);
+             if (es == 0)
+               es = 2; /* strlen ("| ") */
+             name_padding = LONGEST_SIGNAL_DESC - es;
+
+             fprintf (stream, "%*s", name_padding, "");
+
+             if ((WIFSTOPPED (show->status) == 0) &&
+                 (WIFCONTINUED (show->status) == 0) &&
+                 WIFCORED (show->status))
+               fprintf (stream, "(core dumped) ");
+           }
+       }
+
+      if (p != first && format)
+       fprintf (stream, "| ");
+
+      if (p->command)
+       fprintf (stream, "%s", p->command);
+
+      if (p == last && job_index >= 0)
+       {
+         temp = current_working_directory ();
+
+         if (RUNNING (job_index) && (IS_FOREGROUND (job_index) == 0))
+           fprintf (stream, " &");
+
+         if (strcmp (temp, jobs[job_index]->wd) != 0)
+           fprintf (stream,
+             "  (wd: %s)", polite_directory_format (jobs[job_index]->wd));
+       }
+
+      if (format || (p == last))
+       {
+         /* We need to add a CR only if this is an interactive shell, and
+            we're reporting the status of a completed job asynchronously.
+            We can't really check whether this particular job is being
+            reported asynchronously, so just add the CR if the shell is
+            currently interactive and asynchronous notification is enabled. */
+         if (asynchronous_notification && interactive)
+           fprintf (stream, "\r\n");
+         else
+           fprintf (stream, "\n");
+       }
+
+      if (p == last)
+       break;
+      p = p->next;
+    }
+  fflush (stream);
+}
+
+/* Print information to STREAM about jobs[JOB_INDEX] according to FORMAT.
+   Must be called with SIGCHLD blocked or queued with queue_sigchld */
+static void
+pretty_print_job (job_index, format, stream)
+     int job_index, format;
+     FILE *stream;
+{
+  register PROCESS *p;
+
+  /* Format only pid information about the process group leader? */
+  if (format == JLIST_PID_ONLY)
+    {
+      fprintf (stream, "%ld\n", (long)jobs[job_index]->pipe->pid);
+      return;
+    }
+
+  if (format == JLIST_CHANGED_ONLY)
+    {
+      if (IS_NOTIFIED (job_index))
+       return;
+      format = JLIST_STANDARD;
+    }
+
+  if (format != JLIST_NONINTERACTIVE)
+    fprintf (stream, "[%d]%c ", job_index + 1,
+             (job_index == js.j_current) ? '+':
+               (job_index == js.j_previous) ? '-' : ' ');
+
+  if (format == JLIST_NONINTERACTIVE)
+    format = JLIST_LONG;
+
+  p = jobs[job_index]->pipe;
+
+  print_pipeline (p, job_index, format, stream);
+
+  /* We have printed information about this job.  When the job's
+     status changes, waitchld () sets the notification flag to 0. */
+  jobs[job_index]->flags |= J_NOTIFIED;
+}
+
+static int
+print_job (job, format, state, job_index)
+     JOB *job;
+     int format, state, job_index;
+{
+  if (state == -1 || (JOB_STATE)state == job->state)
+    pretty_print_job (job_index, format, stdout);
+  return (0);
+}
+
+void
+list_one_job (job, format, ignore, job_index)
+     JOB *job;
+     int format, ignore, job_index;
+{
+  pretty_print_job (job_index, format, stdout);
+}
+
+void
+list_stopped_jobs (format)
+     int format;
+{
+  cleanup_dead_jobs ();
+  map_over_jobs (print_job, format, (int)JSTOPPED);
+}
+
+void
+list_running_jobs (format)
+     int format;
+{
+  cleanup_dead_jobs ();
+  map_over_jobs (print_job, format, (int)JRUNNING);
+}
+
+/* List jobs.  If FORMAT is non-zero, then the long form of the information
+   is printed, else just a short version. */
+void
+list_all_jobs (format)
+     int format;
+{
+  cleanup_dead_jobs ();
+  map_over_jobs (print_job, format, -1);
+}
+
+/* Fork, handling errors.  Returns the pid of the newly made child, or 0.
+   COMMAND is just for remembering the name of the command; we don't do
+   anything else with it.  ASYNC_P says what to do with the tty.  If
+   non-zero, then don't give it away. */
+pid_t
+make_child (command, async_p)
+     char *command;
+     int async_p;
+{
+  sigset_t set, oset;
+  pid_t pid;
+
+  sigemptyset (&set);
+  sigaddset (&set, SIGCHLD);
+  sigaddset (&set, SIGINT);
+  sigemptyset (&oset);
+  sigprocmask (SIG_BLOCK, &set, &oset);
+
+  making_children ();
+
+#if defined (BUFFERED_INPUT)
+  /* If default_buffered_input is active, we are reading a script.  If
+     the command is asynchronous, we have already duplicated /dev/null
+     as fd 0, but have not changed the buffered stream corresponding to
+     the old fd 0.  We don't want to sync the stream in this case. */
+  if (default_buffered_input != -1 &&
+      (!async_p || default_buffered_input > 0))
+    sync_buffered_stream (default_buffered_input);
+#endif /* BUFFERED_INPUT */
+
+  /* Create the child, handle severe errors. */
+  if ((pid = fork ()) < 0)
+    {
+      sys_error ("fork");
+
+      /* Kill all of the processes in the current pipeline. */
+      terminate_current_pipeline ();
+
+      /* Discard the current pipeline, if any. */
+      if (the_pipeline)
+       kill_current_pipeline ();
+
+      throw_to_top_level ();   /* Reset signals, etc. */
+    }
+
+  if (pid == 0)
+    {
+      /* In the child.  Give this child the right process group, set the
+        signals to the default state for a new process. */
+      pid_t mypid;
+
+      mypid = getpid ();
+#if defined (BUFFERED_INPUT)
+      /* Close default_buffered_input if it's > 0.  We don't close it if it's
+        0 because that's the file descriptor used when redirecting input,
+        and it's wrong to close the file in that case. */
+      unset_bash_input (0);
+#endif /* BUFFERED_INPUT */
+
+      /* Restore top-level signal mask. */
+      sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
+
+      if (job_control)
+       {
+         /* All processes in this pipeline belong in the same
+            process group. */
+
+         if (pipeline_pgrp == 0)       /* This is the first child. */
+           pipeline_pgrp = mypid;
+
+         /* Check for running command in backquotes. */
+         if (pipeline_pgrp == shell_pgrp)
+           ignore_tty_job_signals ();
+         else
+           default_tty_job_signals ();
+
+         /* Set the process group before trying to mess with the terminal's
+            process group.  This is mandated by POSIX. */
+         /* This is in accordance with the Posix 1003.1 standard,
+            section B.7.2.4, which says that trying to set the terminal
+            process group with tcsetpgrp() to an unused pgrp value (like
+            this would have for the first child) is an error.  Section
+            B.4.3.3, p. 237 also covers this, in the context of job control
+            shells. */
+         if (setpgid (mypid, pipeline_pgrp) < 0)
+           sys_error ("child setpgid (%ld to %ld)", (long)mypid, (long)pipeline_pgrp);
+
+         /* By convention (and assumption above), if
+            pipeline_pgrp == shell_pgrp, we are making a child for
+            command substitution.
+            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)
+           give_terminal_to (pipeline_pgrp, 0);
+
+#if defined (PGRP_PIPE)
+         if (pipeline_pgrp == mypid)
+           pipe_read (pgrp_pipe);
+#endif
+       }
+      else                     /* Without job control... */
+       {
+         if (pipeline_pgrp == 0)
+           pipeline_pgrp = shell_pgrp;
+
+         /* If these signals are set to SIG_DFL, we encounter the curious
+            situation of an interactive ^Z to a running process *working*
+            and stopping the process, but being unable to do anything with
+            that process to change its state.  On the other hand, if they
+            are set to SIG_IGN, jobs started from scripts do not stop when
+            the shell running the script gets a SIGTSTP and stops. */
+
+         default_tty_job_signals ();
+       }
+
+#if defined (PGRP_PIPE)
+      /* Release the process group pipe, since our call to setpgid ()
+        is done.  The last call to pipe_close is done in stop_pipeline. */
+      pipe_close (pgrp_pipe);
+#endif /* PGRP_PIPE */
+
+      if (async_p)
+       last_asynchronous_pid = mypid;
+#if defined (RECYCLES_PIDS)
+      else if (last_asynchronous_pid == mypid)
+        /* Avoid pid aliasing.  1 seems like a safe, unusual pid value. */
+       last_asynchronous_pid = 1;
+#endif
+    }
+  else
+    {
+      /* 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;
+itrace("make_child: PID CYCLE: first_pid = %d pid = %d", first_pid, pid);
+}
+      else if (pid_wrap == 0 && pid >= first_pid)
+{
+       pid_wrap = 1;
+itrace("make_child: PID WRAP: first_pid = %d pid = %d", first_pid, pid);
+}
+
+      if (job_control)
+       {
+         if (pipeline_pgrp == 0)
+           {
+             pipeline_pgrp = pid;
+             /* Don't twiddle terminal pgrps in the parent!  This is the bug,
+                not the good thing of twiddling them in the child! */
+             /* give_terminal_to (pipeline_pgrp, 0); */
+           }
+         /* This is done on the recommendation of the Rationale section of
+            the POSIX 1003.1 standard, where it discusses job control and
+            shells.  It is done to avoid possible race conditions. (Ref.
+            1003.1 Rationale, section B.4.3.3, page 236). */
+         setpgid (pid, pipeline_pgrp);
+       }
+      else
+       {
+         if (pipeline_pgrp == 0)
+           pipeline_pgrp = shell_pgrp;
+       }
+
+      /* Place all processes into the jobs array regardless of the
+        state of job_control. */
+      add_process (command, pid);
+
+      if (async_p)
+       last_asynchronous_pid = pid;
+#if defined (RECYCLES_PIDS)
+      else if (last_asynchronous_pid == pid)
+        /* Avoid pid aliasing.  1 seems like a safe, unusual pid value. */
+       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. */
+      if ((js.c_reaped + bgpids.npid) >= js.c_childmax)
+#endif
+       bgp_delete (pid);               /* new process, discard any saved status */
+
+      last_made_pid = pid;
+
+      /* keep stats */
+      js.c_totforked++;
+      js.c_living++;
+
+      /* Unblock SIGINT and SIGCHLD unless creating a pipeline, in which case
+        SIGCHLD remains blocked until all commands in the pipeline have been
+        created. */
+      sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
+    }
+
+  return (pid);
+}
+
+/* These two functions are called only in child processes. */
+void
+ignore_tty_job_signals ()
+{
+  set_signal_handler (SIGTSTP, SIG_IGN);
+  set_signal_handler (SIGTTIN, SIG_IGN);
+  set_signal_handler (SIGTTOU, SIG_IGN);
+}
+
+void
+default_tty_job_signals ()
+{
+  set_signal_handler (SIGTSTP, SIG_DFL);
+  set_signal_handler (SIGTTIN, SIG_DFL);
+  set_signal_handler (SIGTTOU, SIG_DFL);
+}
+
+/* When we end a job abnormally, or if we stop a job, we set the tty to the
+   state kept in here.  When a job ends normally, we set the state in here
+   to the state of the tty. */
+
+static TTYSTRUCT shell_tty_info;
+
+#if defined (NEW_TTY_DRIVER)
+static struct tchars shell_tchars;
+static struct ltchars shell_ltchars;
+#endif /* NEW_TTY_DRIVER */
+
+#if defined (NEW_TTY_DRIVER) && defined (DRAIN_OUTPUT)
+/* Since the BSD tty driver does not allow us to change the tty modes
+   while simultaneously waiting for output to drain and preserving
+   typeahead, we have to drain the output ourselves before calling
+   ioctl.  We cheat by finding the length of the output queue, and
+   using select to wait for an appropriate length of time.  This is
+   a hack, and should be labeled as such (it's a hastily-adapted
+   mutation of a `usleep' implementation).  It's only reason for
+   existing is the flaw in the BSD tty driver. */
+
+static int ttspeeds[] =
+{
+  0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
+  1800, 2400, 4800, 9600, 19200, 38400
+};
+
+static void
+draino (fd, ospeed)
+     int fd, ospeed;
+{
+  register int delay = ttspeeds[ospeed];
+  int n;
+
+  if (!delay)
+    return;
+
+  while ((ioctl (fd, TIOCOUTQ, &n) == 0) && n)
+    {
+      if (n > (delay / 100))
+       {
+         struct timeval tv;
+
+         n *= 10;              /* 2 bits more for conservativeness. */
+         tv.tv_sec = n / delay;
+         tv.tv_usec = ((n % delay) * 1000000) / delay;
+         select (fd, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv);
+       }
+      else
+       break;
+    }
+}
+#endif /* NEW_TTY_DRIVER && DRAIN_OUTPUT */
+
+/* Return the fd from which we are actually getting input. */
+#define input_tty() (shell_tty != -1) ? shell_tty : fileno (stderr)
+
+/* Fill the contents of shell_tty_info with the current tty info. */
+int
+get_tty_state ()
+{
+  int tty;
+
+  tty = input_tty ();
+  if (tty != -1)
+    {
+#if defined (NEW_TTY_DRIVER)
+      ioctl (tty, TIOCGETP, &shell_tty_info);
+      ioctl (tty, TIOCGETC, &shell_tchars);
+      ioctl (tty, TIOCGLTC, &shell_ltchars);
+#endif /* NEW_TTY_DRIVER */
+
+#if defined (TERMIO_TTY_DRIVER)
+      ioctl (tty, TCGETA, &shell_tty_info);
+#endif /* TERMIO_TTY_DRIVER */
+
+#if defined (TERMIOS_TTY_DRIVER)
+      if (tcgetattr (tty, &shell_tty_info) < 0)
+       {
+#if 0
+         /* Only print an error message if we're really interactive at
+            this time. */
+         if (interactive)
+           sys_error ("[%ld: %d] tcgetattr", (long)getpid (), shell_level);
+#endif
+         return -1;
+       }
+#endif /* TERMIOS_TTY_DRIVER */
+      if (check_window_size)
+       get_new_window_size (0, (int *)0, (int *)0);
+    }
+  return 0;
+}
+
+/* Make the current tty use the state in shell_tty_info. */
+int
+set_tty_state ()
+{
+  int tty;
+
+  tty = input_tty ();
+  if (tty != -1)
+    {
+#if defined (NEW_TTY_DRIVER)
+#  if defined (DRAIN_OUTPUT)
+      draino (tty, shell_tty_info.sg_ospeed);
+#  endif /* DRAIN_OUTPUT */
+      ioctl (tty, TIOCSETN, &shell_tty_info);
+      ioctl (tty, TIOCSETC, &shell_tchars);
+      ioctl (tty, TIOCSLTC, &shell_ltchars);
+#endif /* NEW_TTY_DRIVER */
+
+#if defined (TERMIO_TTY_DRIVER)
+      ioctl (tty, TCSETAW, &shell_tty_info);
+#endif /* TERMIO_TTY_DRIVER */
+
+#if defined (TERMIOS_TTY_DRIVER)
+      if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0)
+       {
+         /* Only print an error message if we're really interactive at
+            this time. */
+         if (interactive)
+           sys_error ("[%ld: %d] tcsetattr", (long)getpid (), shell_level);
+         return -1;
+       }
+#endif /* TERMIOS_TTY_DRIVER */
+    }
+  return 0;
+}
+
+/* Given an index into the jobs array JOB, return the PROCESS struct of the last
+   process in that job's pipeline.  This is the one whose exit status
+   counts.  Must be called with SIGCHLD blocked or queued. */
+static PROCESS *
+find_last_proc (job, block)
+     int job;
+     int block;
+{
+  register PROCESS *p;
+  sigset_t set, oset;
+
+  if (block)
+    BLOCK_CHILD (set, oset);
+
+  p = jobs[job]->pipe;
+  while (p && p->next != jobs[job]->pipe)
+    p = p->next;
+
+  if (block)
+    UNBLOCK_CHILD (oset);
+
+  return (p);
+}
+
+static pid_t
+find_last_pid (job, block)
+     int job;
+     int block;
+{
+  PROCESS *p;
+
+  p = find_last_proc (job, block);
+  /* Possible race condition here. */
+  return p->pid;
+}     
+
+/* Wait for a particular child of the shell to finish executing.
+   This low-level function prints an error message if PID is not
+   a child of this shell.  It returns -1 if it fails, or whatever
+   wait_for returns otherwise.  If the child is not found in the
+   jobs table, it returns 127. */
+int
+wait_for_single_pid (pid)
+     pid_t pid;
+{
+  register PROCESS *child;
+  sigset_t set, oset;
+  int r, job;
+
+  BLOCK_CHILD (set, oset);
+  child = find_pipeline (pid, 0, (int *)NULL);
+  UNBLOCK_CHILD (oset);
+
+  if (child == 0)
+    {
+      r = bgp_search (pid);
+      if (r >= 0)
+       return r;
+    }
+
+  if (child == 0)
+    {
+      internal_error (_("wait: pid %ld is not a child of this shell"), (long)pid);
+      return (127);
+    }
+
+  r = wait_for (pid);
+
+  /* POSIX.2: if we just waited for a job, we can remove it from the jobs
+     table. */
+  BLOCK_CHILD (set, oset);
+  job = find_job (pid, 0, NULL);
+  if (job != NO_JOB && jobs[job] && DEADJOB (job))
+    jobs[job]->flags |= J_NOTIFIED;
+  UNBLOCK_CHILD (oset);
+
+  /* If running in posix mode, remove the job from the jobs table immediately */
+  if (posixly_correct)
+    {
+      cleanup_dead_jobs ();
+      bgp_delete (pid);
+    }
+
+  return r;
+}
+
+/* Wait for all of the backgrounds of this shell to finish. */
+void
+wait_for_background_pids ()
+{
+  register int i, r, waited_for;
+  sigset_t set, oset;
+  pid_t pid;
+
+  for (waited_for = 0;;)
+    {
+      BLOCK_CHILD (set, oset);
+
+      /* find first running job; if none running in foreground, break */
+      /* 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;
+       }
+      if (i == js.j_jobslots)
+       {
+         UNBLOCK_CHILD (oset);
+         break;
+       }
+
+      /* now wait for the last pid in that job. */
+      pid = find_last_pid (i, 0);
+      UNBLOCK_CHILD (oset);
+      QUIT;
+      errno = 0;               /* XXX */
+      r = wait_for_single_pid (pid);
+      if (r == -1)
+       {
+         /* If we're mistaken about job state, compensate. */
+         if (errno == ECHILD)
+           mark_all_jobs_as_dead ();
+       }
+      else
+       waited_for++;
+    }
+
+  /* POSIX.2 says the shell can discard the statuses of all completed jobs if
+     `wait' is called with no arguments. */
+  mark_dead_jobs_as_notified (1);
+  cleanup_dead_jobs ();
+  bgp_clear ();
+}
+
+/* Make OLD_SIGINT_HANDLER the SIGINT signal handler. */
+#define INVALID_SIGNAL_HANDLER (SigHandler *)wait_for_background_pids
+static SigHandler *old_sigint_handler = INVALID_SIGNAL_HANDLER;
+
+static void
+restore_sigint_handler ()
+{
+  if (old_sigint_handler != INVALID_SIGNAL_HANDLER)
+    {
+      set_signal_handler (SIGINT, old_sigint_handler);
+      old_sigint_handler = INVALID_SIGNAL_HANDLER;
+    }
+}
+
+static int wait_sigint_received;
+
+/* Handle SIGINT while we are waiting for children in a script to exit.
+   The `wait' builtin should be interruptible, but all others should be
+   effectively ignored (i.e. not cause the shell to exit). */
+static sighandler
+wait_sigint_handler (sig)
+     int sig;
+{
+  SigHandler *sigint_handler;
+
+  if (interrupt_immediately ||
+      (this_shell_builtin && this_shell_builtin == wait_builtin))
+    {
+      last_command_exit_value = EXECUTION_FAILURE;
+      restore_sigint_handler ();
+      /* If we got a SIGINT while in `wait', and SIGINT is trapped, do
+        what POSIX.2 says (see builtins/wait.def for more info). */
+      if (this_shell_builtin && this_shell_builtin == wait_builtin &&
+         signal_is_trapped (SIGINT) &&
+         ((sigint_handler = trap_to_sighandler (SIGINT)) == trap_handler))
+       {
+         interrupt_immediately = 0;
+         trap_handler (SIGINT);        /* set pending_traps[SIGINT] */
+         wait_signal_received = SIGINT;
+         longjmp (wait_intr_buf, 1);
+       }
+      
+      ADDINTERRUPT;
+      QUIT;
+    }
+
+  /* XXX - should this be interrupt_state?  If it is, the shell will act
+     as if it got the SIGINT interrupt. */
+  wait_sigint_received = 1;
+
+  /* Otherwise effectively ignore the SIGINT and allow the running job to
+     be killed. */
+  SIGRETURN (0);
+}
+
+static int
+process_exit_signal (status)
+     WAIT status;
+{
+  return (WIFSIGNALED (status) ? WTERMSIG (status) : 0);
+}
+
+static int
+process_exit_status (status)
+     WAIT status;
+{
+  if (WIFSIGNALED (status))
+    return (128 + WTERMSIG (status));
+  else if (WIFSTOPPED (status) == 0)
+    return (WEXITSTATUS (status));
+  else
+    return (EXECUTION_SUCCESS);
+}
+
+/* Return the exit status of the last process in the pipeline for job JOB.
+   This is the exit status of the entire job. */
+static WAIT
+raw_job_exit_status (job)
+     int job;
+{
+  register PROCESS *p;
+  int fail;
+
+  if (pipefail_opt)
+    {
+      fail = 0;
+      p = jobs[job]->pipe;
+      do
+       {
+         if (p->status != EXECUTION_SUCCESS) fail = p->status;
+         p = p->next;
+       }
+      while (p != jobs[job]->pipe);
+      return fail;
+    }
+
+  for (p = jobs[job]->pipe; p->next != jobs[job]->pipe; p = p->next)
+    ;
+  return (p->status);
+}
+
+/* Return the exit status of job JOB.  This is the exit status of the last
+   (rightmost) process in the job's pipeline, modified if the job was killed
+   by a signal or stopped. */
+static int
+job_exit_status (job)
+     int job;
+{
+  return (process_exit_status (raw_job_exit_status (job)));
+}
+
+static int
+job_exit_signal (job)
+     int job;
+{
+  return (process_exit_signal (raw_job_exit_status (job)));
+}
+
+#define FIND_CHILD(pid, child) \
+  do \
+    { \
+      child = find_pipeline (pid, 0, (int *)NULL); \
+      if (child == 0) \
+       { \
+         give_terminal_to (shell_pgrp, 0); \
+         UNBLOCK_CHILD (oset); \
+         internal_error (_("wait_for: No record of process %ld"), (long)pid); \
+         restore_sigint_handler (); \
+         return (termination_state = 127); \
+       } \
+    } \
+  while (0)
+
+/* Wait for pid (one of our children) to terminate, then
+   return the termination state.  Returns 127 if PID is not found in
+   the jobs table.  Returns -1 if waitchld() returns -1, indicating
+   that there are no unwaited-for child processes. */
+int
+wait_for (pid)
+     pid_t pid;
+{
+  int job, termination_state, r;
+  WAIT s;
+  register PROCESS *child;
+  sigset_t set, oset;
+  register PROCESS *p;
+
+  /* In the case that this code is interrupted, and we longjmp () out of it,
+     we are relying on the code in throw_to_top_level () to restore the
+     top-level signal mask. */
+  BLOCK_CHILD (set, oset);
+
+  /* Ignore interrupts while waiting for a job run without job control
+     to finish.  We don't want the shell to exit if an interrupt is
+     received, only if one of the jobs run is killed via SIGINT.  If
+     job control is not set, the job will be run in the same pgrp as
+     the shell, and the shell will see any signals the job gets. */
+
+  /* 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);
+
+  termination_state = last_command_exit_value;
+
+  if (interactive && job_control == 0)
+    QUIT;
+
+  /* If we say wait_for (), then we have a record of this child somewhere.
+     If it and none of its peers are running, don't call waitchld(). */
+
+  job = NO_JOB;
+  do
+    {
+      FIND_CHILD (pid, child);
+
+      /* If this child is part of a job, then we are really waiting for the
+        job to finish.  Otherwise, we are waiting for the child to finish.
+        We check for JDEAD in case the job state has been set by waitchld
+        after receipt of a SIGCHLD. */
+      if (job == NO_JOB)
+       job = find_job (pid, 0, NULL);
+
+      /* waitchld() takes care of setting the state of the job.  If the job
+        has already exited before this is called, sigchld_handler will have
+        called waitchld and the state will be set to JDEAD. */
+
+      if (PRUNNING(child) || (job != NO_JOB && RUNNING (job)))
+       {
+#if defined (WAITPID_BROKEN)    /* SCOv4 */
+         sigset_t suspend_set;
+         sigemptyset (&suspend_set);
+         sigsuspend (&suspend_set);
+#else /* !WAITPID_BROKEN */
+#  if defined (MUST_UNBLOCK_CHLD)
+         struct sigaction act, oact;
+         sigset_t nullset, chldset;
+
+         sigemptyset (&nullset);
+         sigemptyset (&chldset);
+         sigprocmask (SIG_SETMASK, &nullset, &chldset);
+         act.sa_handler = SIG_DFL;
+         sigemptyset (&act.sa_mask);
+         sigemptyset (&oact.sa_mask);
+         act.sa_flags = 0;
+         sigaction (SIGCHLD, &act, &oact);
+#  endif
+         queue_sigchld = 1;
+         r = waitchld (pid, 1);
+#  if defined (MUST_UNBLOCK_CHLD)
+         sigaction (SIGCHLD, &oact, (struct sigaction *)NULL);
+         sigprocmask (SIG_SETMASK, &chldset, (sigset_t *)NULL);
+#  endif
+         queue_sigchld = 0;
+         if (r == -1 && errno == ECHILD && this_shell_builtin == wait_builtin)
+           {
+             termination_state = -1;
+             goto wait_for_return;
+           }
+
+         /* If child is marked as running, but waitpid() returns -1/ECHILD,
+            there is something wrong.  Somewhere, wait should have returned
+            that child's pid.  Mark the child as not running and the job,
+            if it exists, as JDEAD. */
+         if (r == -1 && errno == ECHILD)
+           {
+             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;
+                 js.c_reaped++;
+                 js.j_ndead++;
+               }
+           }
+#endif /* WAITPID_BROKEN */
+       }
+
+      /* If the shell is interactive, and job control is disabled, see
+        if the foreground process has died due to SIGINT and jump out
+        of the wait loop if it has.  waitchld has already restored the
+        old SIGINT signal handler. */
+      if (interactive && job_control == 0)
+       QUIT;
+    }
+  while (PRUNNING (child) || (job != NO_JOB && RUNNING (job)));
+
+  /* The exit state of the command is either the termination state of the
+     child, or the termination state of the job.  If a job, the status
+     of the last child in the pipeline is the significant one.  If the command
+     or job was terminated by a signal, note that value also. */
+  termination_state = (job != NO_JOB) ? job_exit_status (job)
+                                     : process_exit_status (child->status);
+  last_command_exit_signal = (job != NO_JOB) ? job_exit_signal (job)
+                                            : process_exit_signal (child->status);
+
+  /* XXX */
+  if ((job != NO_JOB && JOBSTATE (job) == JSTOPPED) || WIFSTOPPED (child->status))
+    termination_state = 128 + WSTOPSIG (child->status);
+
+  if (job == NO_JOB || IS_JOBCONTROL (job))
+    {
+      /* XXX - under what circumstances is a job not present in the jobs
+        table (job == NO_JOB)?
+               1.  command substitution
+
+        In the case of command substitution, at least, it's probably not
+        the right thing to give the terminal to the shell's process group,
+        even though there is code in subst.c:command_substitute to work
+        around it.
+
+        Things that don't:
+               $PROMPT_COMMAND execution
+               process substitution
+       */
+#if 0
+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);
+    }
+
+  /* If the command did not exit cleanly, or the job is just
+     being stopped, then reset the tty state back to what it
+     was before this command.  Reset the tty state and notify
+     the user of the job termination only if the shell is
+     interactive.  Clean up any dead jobs in either case. */
+  if (job != NO_JOB)
+    {
+      if (interactive_shell && subshell_environment == 0)
+       {
+         /* This used to use `child->status'.  That's wrong, however, for
+            pipelines.  `child' is the first process in the pipeline.  It's
+            likely that the process we want to check for abnormal termination
+            or stopping is the last process in the pipeline, especially if
+            it's long-lived and the first process is short-lived.  Since we
+            know we have a job here, we can check all the processes in this
+            job's pipeline and see if one of them stopped or terminated due
+            to a signal.  We might want to change this later to just check
+            the last process in the pipeline.  If no process exits due to a
+            signal, S is left as the status of the last job in the pipeline. */
+         p = jobs[job]->pipe;
+         do
+           {
+             s = p->status;
+             if (WIFSIGNALED(s) || WIFSTOPPED(s))
+               break;
+             p = p->next;
+           }
+         while (p != jobs[job]->pipe);
+
+         if (WIFSIGNALED (s) || WIFSTOPPED (s))
+           {
+             set_tty_state ();
+
+             /* If the current job was stopped or killed by a signal, and
+                the user has requested it, get a possibly new window size */
+             if (check_window_size && (job == js.j_current || IS_FOREGROUND (job)))
+               get_new_window_size (0, (int *)0, (int *)0);
+           }
+         else
+           get_tty_state ();
+
+         /* If job control is enabled, the job was started with job
+            control, the job was the foreground job, and it was killed
+            by SIGINT, then print a newline to compensate for the kernel
+            printing the ^C without a trailing newline. */
+         if (job_control && IS_JOBCONTROL (job) && IS_FOREGROUND (job) &&
+               WIFSIGNALED (s) && WTERMSIG (s) == SIGINT)
+           {
+             /* If SIGINT is not trapped and the shell is in a for, while,
+                or until loop, act as if the shell received SIGINT as
+                well, so the loop can be broken.  This doesn't call the
+                SIGINT signal handler; maybe it should. */
+             if (signal_is_trapped (SIGINT) == 0 && loop_level)
+               ADDINTERRUPT;
+             else
+               {
+                 putchar ('\n');
+                 fflush (stdout);
+               }
+           }
+       }
+
+      /* Moved here from set_job_status_and_cleanup, which is in the SIGCHLD
+         signal handler path */
+      if (DEADJOB (job) && IS_FOREGROUND (job) /*&& subshell_environment == 0*/)
+       setjstatus (job);
+
+      /* If this job is dead, notify the user of the status.  If the shell
+        is interactive, this will display a message on the terminal.  If
+        the shell is not interactive, make sure we turn on the notify bit
+        so we don't get an unwanted message about the job's termination,
+        and so delete_job really clears the slot in the jobs table. */
+      notify_and_cleanup ();
+    }
+
+wait_for_return:
+
+  UNBLOCK_CHILD (oset);
+
+  /* Restore the original SIGINT signal handler before we return. */
+  restore_sigint_handler ();
+
+  return (termination_state);
+}
+
+/* Wait for the last process in the pipeline for JOB.  Returns whatever
+   wait_for returns: the last process's termination state or -1 if there
+   are no unwaited-for child processes or an error occurs. */
+int
+wait_for_job (job)
+     int job;
+{
+  pid_t pid;
+  int r;
+  sigset_t set, oset;
+
+  BLOCK_CHILD(set, oset);
+  if (JOBSTATE (job) == JSTOPPED)
+    internal_warning (_("wait_for_job: job %d is stopped"), job+1);
+
+  pid = find_last_pid (job, 0);
+  UNBLOCK_CHILD(oset);
+  r = wait_for (pid);
+
+  /* POSIX.2: we can remove the job from the jobs table if we just waited
+     for it. */
+  BLOCK_CHILD (set, oset);
+  if (job != NO_JOB && jobs[job] && DEADJOB (job))
+    jobs[job]->flags |= J_NOTIFIED;
+  UNBLOCK_CHILD (oset);
+
+  return r;
+}
+
+/* Print info about dead jobs, and then delete them from the list
+   of known jobs.  This does not actually delete jobs when the
+   shell is not interactive, because the dead jobs are not marked
+   as notified. */
+void
+notify_and_cleanup ()
+{
+  if (jobs_list_frozen)
+    return;
+
+  if (interactive || interactive_shell == 0 || sourcelevel)
+    notify_of_job_status ();
+
+  cleanup_dead_jobs ();
+}
+
+/* Make dead jobs disappear from the jobs array without notification.
+   This is used when the shell is not interactive. */
+void
+reap_dead_jobs ()
+{
+  mark_dead_jobs_as_notified (0);
+  cleanup_dead_jobs ();
+}
+
+/* Return the next closest (chronologically) job to JOB which is in
+   STATE.  STATE can be JSTOPPED, JRUNNING.  NO_JOB is returned if
+   there is no next recent job. */
+static int
+most_recent_job_in_state (job, state)
+     int job;
+     JOB_STATE state;
+{
+  register int i, result;
+  sigset_t set, oset;
+
+  BLOCK_CHILD (set, oset);
+
+  for (result = NO_JOB, i = job - 1; i >= 0; i--)
+    {
+      if (jobs[i] && (JOBSTATE (i) == state))
+       {
+         result = i;
+         break;
+       }
+    }
+
+  UNBLOCK_CHILD (oset);
+
+  return (result);
+}
+
+/* Return the newest *stopped* job older than JOB, or NO_JOB if not
+   found. */
+static int
+job_last_stopped (job)
+     int job;
+{
+  return (most_recent_job_in_state (job, JSTOPPED));
+}
+
+/* Return the newest *running* job older than JOB, or NO_JOB if not
+   found. */
+static int
+job_last_running (job)
+     int job;
+{
+  return (most_recent_job_in_state (job, JRUNNING));
+}
+
+/* Make JOB be the current job, and make previous be useful.  Must be
+   called with SIGCHLD blocked. */
+static void
+set_current_job (job)
+     int job;
+{
+  int candidate;
+
+  if (js.j_current != job)
+    {
+      js.j_previous = js.j_current;
+      js.j_current = job;
+    }
+
+  /* First choice for previous job is the old current job. */
+  if (js.j_previous != js.j_current &&
+      js.j_previous != NO_JOB &&
+      jobs[js.j_previous] &&
+      STOPPED (js.j_previous))
+    return;
+
+  /* Second choice:  Newest stopped job that is older than
+     the current job. */
+  candidate = NO_JOB;
+  if (STOPPED (js.j_current))
+    {
+      candidate = job_last_stopped (js.j_current);
+
+      if (candidate != NO_JOB)
+       {
+         js.j_previous = candidate;
+         return;
+       }
+    }
+
+  /* If we get here, there is either only one stopped job, in which case it is
+     the current job and the previous job should be set to the newest running
+     job, or there are only running jobs and the previous job should be set to
+     the newest running job older than the current job.  We decide on which
+     alternative to use based on whether or not JOBSTATE(js.j_current) is
+     JSTOPPED. */
+
+  candidate = RUNNING (js.j_current) ? job_last_running (js.j_current)
+                                   : job_last_running (js.j_jobslots);
+
+  if (candidate != NO_JOB)
+    {
+      js.j_previous = candidate;
+      return;
+    }
+
+  /* There is only a single job, and it is both `+' and `-'. */
+  js.j_previous = js.j_current;
+}
+
+/* Make current_job be something useful, if it isn't already. */
+
+/* Here's the deal:  The newest non-running job should be `+', and the
+   next-newest non-running job should be `-'.  If there is only a single
+   stopped job, the js.j_previous is the newest non-running job.  If there
+   are only running jobs, the newest running job is `+' and the
+   next-newest running job is `-'.  Must be called with SIGCHLD blocked. */
+
+static void
+reset_current ()
+{
+  int candidate;
+
+  if (js.j_jobslots && js.j_current != NO_JOB && jobs[js.j_current] && STOPPED (js.j_current))
+    candidate = js.j_current;
+  else
+    {
+      candidate = NO_JOB;
+
+      /* First choice: the previous job. */
+      if (js.j_previous != NO_JOB && jobs[js.j_previous] && STOPPED (js.j_previous))
+       candidate = js.j_previous;
+
+      /* Second choice: the most recently stopped job. */
+      if (candidate == NO_JOB)
+       candidate = job_last_stopped (js.j_jobslots);
+
+      /* Third choice: the newest running job. */
+      if (candidate == NO_JOB)
+       candidate = job_last_running (js.j_jobslots);
+    }
+
+  /* If we found a job to use, then use it.  Otherwise, there
+     are no jobs period. */
+  if (candidate != NO_JOB)
+    set_current_job (candidate);
+  else
+    js.j_current = js.j_previous = NO_JOB;
+}
+
+/* Set up the job structures so we know the job and its processes are
+   all running. */
+static void
+set_job_running (job)
+     int job;
+{
+  register PROCESS *p;
+
+  /* Each member of the pipeline is now running. */
+  p = jobs[job]->pipe;
+
+  do
+    {
+      if (WIFSTOPPED (p->status))
+       p->running = PS_RUNNING;        /* XXX - could be PS_STOPPED */
+      p = p->next;
+    }
+  while (p != jobs[job]->pipe);
+
+  /* This means that the job is running. */
+  JOBSTATE (job) = JRUNNING;
+}
+
+/* Start a job.  FOREGROUND if non-zero says to do that.  Otherwise,
+   start the job in the background.  JOB is a zero-based index into
+   JOBS.  Returns -1 if it is unable to start a job, and the return
+   status of the job otherwise. */
+int
+start_job (job, foreground)
+     int job, foreground;
+{
+  register PROCESS *p;
+  int already_running;
+  sigset_t set, oset;
+  char *wd, *s;
+  static TTYSTRUCT save_stty;
+
+  BLOCK_CHILD (set, oset);
+
+  if (DEADJOB (job))
+    {
+      internal_error (_("%s: job has terminated"), this_command_name);
+      UNBLOCK_CHILD (oset);
+      return (-1);
+    }
+
+  already_running = RUNNING (job);
+
+  if (foreground == 0 && already_running)
+    {
+      internal_error (_("%s: job %d already in background"), this_command_name, job + 1);
+      UNBLOCK_CHILD (oset);
+      return (0);              /* XPG6/SUSv3 says this is not an error */
+    }
+
+  wd = current_working_directory ();
+
+  /* You don't know about the state of this job.  Do you? */
+  jobs[job]->flags &= ~J_NOTIFIED;
+
+  if (foreground)
+    {
+      set_current_job (job);
+      jobs[job]->flags |= J_FOREGROUND;
+    }
+
+  /* Tell the outside world what we're doing. */
+  p = jobs[job]->pipe;
+
+  if (foreground == 0)
+    {
+      /* POSIX.2 says `bg' doesn't give any indication about current or
+        previous job. */
+      if (posixly_correct == 0)
+       s = (job == js.j_current) ? "+ ": ((job == js.j_previous) ? "- " : " ");       
+      else
+       s = " ";
+      printf ("[%d]%s", job + 1, s);
+    }
+
+  do
+    {
+      printf ("%s%s",
+              p->command ? p->command : "",
+              p->next != jobs[job]->pipe? " | " : "");
+      p = p->next;
+    }
+  while (p != jobs[job]->pipe);
+
+  if (foreground == 0)
+    printf (" &");
+
+  if (strcmp (wd, jobs[job]->wd) != 0)
+    printf ("  (wd: %s)", polite_directory_format (jobs[job]->wd));
+
+  printf ("\n");
+
+  /* Run the job. */
+  if (already_running == 0)
+    set_job_running (job);
+
+  /* Save the tty settings before we start the job in the foreground. */
+  if (foreground)
+    {
+      get_tty_state ();
+      save_stty = shell_tty_info;
+      /* Give the terminal to this job. */
+      if (IS_JOBCONTROL (job))
+       give_terminal_to (jobs[job]->pgrp, 0);
+    }
+  else
+    jobs[job]->flags &= ~J_FOREGROUND;
+
+  /* If the job is already running, then don't bother jump-starting it. */
+  if (already_running == 0)
+    {
+      jobs[job]->flags |= J_NOTIFIED;
+      killpg (jobs[job]->pgrp, SIGCONT);
+    }
+
+  if (foreground)
+    {
+      pid_t pid;
+      int s;
+
+      pid = find_last_pid (job, 0);
+      UNBLOCK_CHILD (oset);
+      s = wait_for (pid);
+      shell_tty_info = save_stty;
+      set_tty_state ();
+      return (s);
+    }
+  else
+    {
+      reset_current ();
+      UNBLOCK_CHILD (oset);
+      return (0);
+    }
+}
+
+/* Give PID SIGNAL.  This determines what job the pid belongs to (if any).
+   If PID does belong to a job, and the job is stopped, then CONTinue the
+   job after giving it SIGNAL.  Returns -1 on failure.  If GROUP is non-null,
+   then kill the process group associated with PID. */
+int
+kill_pid (pid, sig, group)
+     pid_t pid;
+     int sig, group;
+{
+  register PROCESS *p;
+  int job, result, negative;
+  sigset_t set, oset;
+
+  if (pid < -1)
+    {
+      pid = -pid;
+      group = negative = 1;
+    }
+  else
+    negative = 0;
+
+  result = EXECUTION_SUCCESS;
+  if (group)
+    {
+      BLOCK_CHILD (set, oset);
+      p = find_pipeline (pid, 0, &job);
+
+      if (job != NO_JOB)
+       {
+         jobs[job]->flags &= ~J_NOTIFIED;
+
+         /* Kill process in backquotes or one started without job control? */
+
+         /* If we're passed a pid < -1, just call killpg and see what happens  */
+         if (negative && jobs[job]->pgrp == shell_pgrp)
+           result = killpg (pid, sig);
+         /* If we're killing using job control notification, for example,
+            without job control active, we have to do things ourselves. */
+         else if (jobs[job]->pgrp == shell_pgrp)
+           {
+             p = jobs[job]->pipe;
+             do
+               {
+                 if (PALIVE (p) == 0)
+                   continue;           /* avoid pid recycling problem */
+                 kill (p->pid, sig);
+                 if (PEXITED (p) && (sig == SIGTERM || sig == SIGHUP))
+                   kill (p->pid, SIGCONT);
+                 p = p->next;
+               }
+             while  (p != jobs[job]->pipe);
+           }
+         else
+           {
+             result = killpg (jobs[job]->pgrp, sig);
+             if (p && STOPPED (job) && (sig == SIGTERM || sig == SIGHUP))
+               killpg (jobs[job]->pgrp, SIGCONT);
+             /* If we're continuing a stopped job via kill rather than bg or
+                fg, emulate the `bg' behavior. */
+             if (p && STOPPED (job) && (sig == SIGCONT))
+               {
+                 set_job_running (job);
+                 jobs[job]->flags &= ~J_FOREGROUND;
+                 jobs[job]->flags |= J_NOTIFIED;
+               }
+           }
+       }
+      else
+       result = killpg (pid, sig);
+
+      UNBLOCK_CHILD (oset);
+    }
+  else
+    result = kill (pid, sig);
+
+  return (result);
+}
+
+/* sigchld_handler () flushes at least one of the children that we are
+   waiting for.  It gets run when we have gotten a SIGCHLD signal. */
+static sighandler
+sigchld_handler (sig)
+     int sig;
+{
+  int n, oerrno;
+
+  oerrno = errno;
+  REINSTALL_SIGCHLD_HANDLER;
+  sigchld++;
+  n = 0;
+  if (queue_sigchld == 0)
+    n = waitchld (-1, 0);
+  errno = oerrno;
+  SIGRETURN (n);
+}
+
+/* waitchld() reaps dead or stopped children.  It's called by wait_for and
+   sigchld_handler, and runs until there aren't any children terminating any
+   more.
+   If BLOCK is 1, this is to be a blocking wait for a single child, although
+   an arriving SIGCHLD could cause the wait to be non-blocking.  It returns
+   the number of children reaped, or -1 if there are no unwaited-for child
+   processes. */
+static int
+waitchld (wpid, block)
+     pid_t wpid;
+     int block;
+{
+  WAIT status;
+  PROCESS *child;
+  pid_t pid;
+  int call_set_current, last_stopped_job, job, children_exited, waitpid_flags;
+  static int wcontinued = WCONTINUED;  /* run-time fix for glibc problem */
+
+  call_set_current = children_exited = 0;
+  last_stopped_job = NO_JOB;
+
+  do
+    {
+      /* We don't want to be notified about jobs stopping if job control
+        is not active.  XXX - was interactive_shell instead of job_control */
+      waitpid_flags = (job_control && subshell_environment == 0)
+                       ? (WUNTRACED|wcontinued)
+                       : 0;
+      if (sigchld || block == 0)
+       waitpid_flags |= WNOHANG;
+      pid = WAITPID (-1, &status, waitpid_flags);
+
+      /* WCONTINUED may be rejected by waitpid as invalid even when defined */
+      if (wcontinued && pid < 0 && errno == EINVAL)
+       {
+         wcontinued = 0;
+         continue;     /* jump back to the test and retry without WCONTINUED */
+       }
+
+      /* The check for WNOHANG is to make sure we decrement sigchld only
+        if it was non-zero before we called waitpid. */
+      if (sigchld > 0 && (waitpid_flags & WNOHANG))
+       sigchld--;
+  
+      /* If waitpid returns -1 with errno == ECHILD, there are no more
+        unwaited-for child processes of this shell. */
+      if (pid < 0 && errno == ECHILD)
+       {
+         if (children_exited == 0)
+           return -1;
+         else
+           break;
+       }
+
+      /* If waitpid returns 0, there are running children.  If it returns -1,
+        the only other error POSIX says it can return is EINTR. */
+      if (pid <= 0)
+       continue;       /* jumps right to the test */
+
+      /* 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++;
+         js.c_living--;
+       }
+
+      /* Locate our PROCESS for this pid. */
+      child = find_process (pid, 1, &job);     /* want living procs only */
+
+      /* It is not an error to have a child terminate that we did
+        not have a record of.  This child could have been part of
+        a pipeline in backquote substitution.  Even so, I'm not
+        sure child is ever non-zero. */
+      if (child == 0)
+       continue;
+
+      /* Remember status, and whether or not the process is running. */
+      child->status = status;
+      child->running = WIFCONTINUED(status) ? PS_RUNNING : PS_DONE;
+
+      if (PEXITED (child))
+       {
+         js.c_totreaped++;
+         if (job != NO_JOB)
+           js.c_reaped++;
+       }
+        
+      if (job == NO_JOB)
+       continue;
+
+      call_set_current += set_job_status_and_cleanup (job);
+
+      if (STOPPED (job))
+       last_stopped_job = job;
+      else if (DEADJOB (job) && last_stopped_job == job)
+       last_stopped_job = NO_JOB;
+    }
+  while ((sigchld || block == 0) && pid > (pid_t)0);
+
+  /* If a job was running and became stopped, then set the current
+     job.  Otherwise, don't change a thing. */
+  if (call_set_current)
+    {
+      if (last_stopped_job != NO_JOB)
+       set_current_job (last_stopped_job);
+      else
+       reset_current ();
+    }
+
+  /* Call a SIGCHLD trap handler for each child that exits, if one is set. */
+  if (job_control && signal_is_trapped (SIGCHLD) && children_exited &&
+      trap_list[SIGCHLD] != (char *)IGNORE_SIG)
+    run_sigchld_trap (children_exited);
+
+  /* We have successfully recorded the useful information about this process
+     that has just changed state.  If we notify asynchronously, and the job
+     that this process belongs to is no longer running, then notify the user
+     of that fact now. */
+  if (asynchronous_notification && interactive)
+    notify_of_job_status ();
+
+  return (children_exited);
+}
+
+/* Set the status of JOB and perform any necessary cleanup if the job is
+   marked as JDEAD.
+
+   Currently, the cleanup activity is restricted to handling any SIGINT
+   received while waiting for a foreground job to finish. */
+static int
+set_job_status_and_cleanup (job)
+     int job;
+{
+  PROCESS *child;
+  int tstatus, job_state, any_stopped, any_tstped, call_set_current;
+  SigHandler *temp_handler;
+
+  child = jobs[job]->pipe;
+  jobs[job]->flags &= ~J_NOTIFIED;
+
+  call_set_current = 0;
+
+  /*
+   * COMPUTE JOB STATUS
+   */
+
+  /* If all children are not running, but any of them is  stopped, then
+     the job is stopped, not dead. */
+  job_state = any_stopped = any_tstped = 0;
+  do
+    {
+      job_state |= PRUNNING (child);
+#if 0
+      if (PEXITED (child) && (WIFSTOPPED (child->status)))
+#else
+      /* Only checking for WIFSTOPPED now, not for PS_DONE */
+      if (PSTOPPED (child))
+#endif
+       {
+         any_stopped = 1;
+         any_tstped |= interactive && job_control &&
+                           (WSTOPSIG (child->status) == SIGTSTP);
+       }
+      child = child->next;
+    }
+  while (child != jobs[job]->pipe);
+
+  /* If job_state != 0, the job is still running, so don't bother with
+     setting the process exit status and job state unless we're
+     transitioning from stopped to running. */
+  if (job_state != 0 && JOBSTATE(job) != JSTOPPED)
+    return 0;
+
+  /*
+   * SET JOB STATUS
+   */
+
+  /* The job is either stopped or dead.  Set the state of the job accordingly. */
+  if (any_stopped)
+    {
+      jobs[job]->state = JSTOPPED;
+      jobs[job]->flags &= ~J_FOREGROUND;
+      call_set_current++;
+      /* Suspending a job with SIGTSTP breaks all active loops. */
+      if (any_tstped && loop_level)
+       breaking = loop_level;
+    }
+  else if (job_state != 0)     /* was stopped, now running */
+    {
+      jobs[job]->state = JRUNNING;
+      call_set_current++;
+    }
+  else
+    {
+      jobs[job]->state = JDEAD;
+      js.j_ndead++;
+
+#if 0
+      if (IS_FOREGROUND (job))
+       setjstatus (job);
+#endif
+
+      /* If this job has a cleanup function associated with it, call it
+        with `cleanarg' as the single argument, then set the function
+        pointer to NULL so it is not inadvertently called twice.  The
+        cleanup function is responsible for deallocating cleanarg. */
+      if (jobs[job]->j_cleanup)
+       {
+         (*jobs[job]->j_cleanup) (jobs[job]->cleanarg);
+         jobs[job]->j_cleanup = (sh_vptrfunc_t *)NULL;
+       }
+    }
+
+  /*
+   * CLEANUP
+   *
+   * Currently, we just do special things if we got a SIGINT while waiting
+   * for a foreground job to complete
+   */
+
+  if (JOBSTATE (job) == JDEAD)
+    {
+      /* If we're running a shell script and we get a SIGINT with a
+        SIGINT trap handler, but the foreground job handles it and
+        does not exit due to SIGINT, run the trap handler but do not
+        otherwise act as if we got the interrupt. */
+      if (wait_sigint_received && interactive_shell == 0 &&
+         WIFSIGNALED (child->status) == 0 && IS_FOREGROUND (job) &&
+         signal_is_trapped (SIGINT))
+       {
+         int old_frozen;
+         wait_sigint_received = 0;
+         last_command_exit_value = process_exit_status (child->status);
+
+         old_frozen = jobs_list_frozen;
+         jobs_list_frozen = 1;
+         tstatus = maybe_call_trap_handler (SIGINT);
+         jobs_list_frozen = old_frozen;
+       }
+
+      /* If the foreground job is killed by SIGINT when job control is not
+        active, we need to perform some special handling.
+
+        The check of wait_sigint_received is a way to determine if the
+        SIGINT came from the keyboard (in which case the shell has already
+        seen it, and wait_sigint_received is non-zero, because keyboard
+        signals are sent to process groups) or via kill(2) to the foreground
+        process by another process (or itself).  If the shell did receive the
+        SIGINT, it needs to perform normal SIGINT processing. */
+      else if (wait_sigint_received && (WTERMSIG (child->status) == SIGINT) &&
+             IS_FOREGROUND (job) && IS_JOBCONTROL (job) == 0)
+       {
+         int old_frozen;
+
+         wait_sigint_received = 0;
+
+         /* If SIGINT is trapped, set the exit status so that the trap
+            handler can see it. */
+         if (signal_is_trapped (SIGINT))
+           last_command_exit_value = process_exit_status (child->status);
+
+         /* If the signal is trapped, let the trap handler get it no matter
+            what and simply return if the trap handler returns.
+           maybe_call_trap_handler() may cause dead jobs to be removed from
+           the job table because of a call to execute_command.  We work
+           around this by setting JOBS_LIST_FROZEN. */
+         old_frozen = jobs_list_frozen;
+         jobs_list_frozen = 1;
+         tstatus = maybe_call_trap_handler (SIGINT);
+         jobs_list_frozen = old_frozen;
+         if (tstatus == 0 && old_sigint_handler != INVALID_SIGNAL_HANDLER)
+           {
+             /* wait_sigint_handler () has already seen SIGINT and
+                allowed the wait builtin to jump out.  We need to
+                call the original SIGINT handler, if necessary.  If
+                the original handler is SIG_DFL, we need to resend
+                the signal to ourselves. */
+
+             temp_handler = old_sigint_handler;
+
+             /* Bogus.  If we've reset the signal handler as the result
+                of a trap caught on SIGINT, then old_sigint_handler
+                will point to trap_handler, which now knows nothing about
+                SIGINT (if we reset the sighandler to the default).
+                In this case, we have to fix things up.  What a crock. */
+             if (temp_handler == trap_handler && signal_is_trapped (SIGINT) == 0)
+                 temp_handler = trap_to_sighandler (SIGINT);
+               restore_sigint_handler ();
+             if (temp_handler == SIG_DFL)
+               termination_unwind_protect (SIGINT);
+             else if (temp_handler != SIG_IGN)
+               (*temp_handler) (SIGINT);
+           }
+       }
+    }
+
+  return call_set_current;
+}
+
+/* Build the array of values for the $PIPESTATUS variable from the set of
+   exit statuses of all processes in the job J. */
+static void
+setjstatus (j)
+     int j;
+{
+#if defined (ARRAY_VARS)
+  register int i;
+  register PROCESS *p;
+
+  for (i = 1, p = jobs[j]->pipe; p->next != jobs[j]->pipe; p = p->next, i++)
+    ;
+  i++;
+  if (statsize < i)
+    {
+      pstatuses = (int *)xrealloc (pstatuses, i * sizeof (int));
+      statsize = i;
+    }
+  i = 0;
+  p = jobs[j]->pipe;
+  do
+    {
+      pstatuses[i++] = process_exit_status (p->status);
+      p = p->next;
+    }
+  while (p != jobs[j]->pipe);
+
+  pstatuses[i] = -1;   /* sentinel */
+  set_pipestatus_array (pstatuses, i);
+#endif
+}
+
+static void
+run_sigchld_trap (nchild)
+     int nchild;
+{
+  char *trap_command;
+  int i;
+
+  /* Turn off the trap list during the call to parse_and_execute ()
+     to avoid potentially infinite recursive calls.  Preserve the
+     values of last_command_exit_value, last_made_pid, and the_pipeline
+     around the execution of the trap commands. */
+  trap_command = savestring (trap_list[SIGCHLD]);
+
+  begin_unwind_frame ("SIGCHLD trap");
+  unwind_protect_int (last_command_exit_value);
+  unwind_protect_int (last_command_exit_signal);
+  unwind_protect_var (last_made_pid);
+  unwind_protect_int (interrupt_immediately);
+  unwind_protect_int (jobs_list_frozen);
+  unwind_protect_pointer (the_pipeline);
+  unwind_protect_pointer (subst_assign_varlist);
+
+  /* We have to add the commands this way because they will be run
+     in reverse order of adding.  We don't want maybe_set_sigchld_trap ()
+     to reference freed memory. */
+  add_unwind_protect (xfree, trap_command);
+  add_unwind_protect (maybe_set_sigchld_trap, trap_command);
+
+  subst_assign_varlist = (WORD_LIST *)NULL;
+  the_pipeline = (PROCESS *)NULL;
+
+  restore_default_signal (SIGCHLD);
+  jobs_list_frozen = 1;
+  for (i = 0; i < nchild; i++)
+    {
+      interrupt_immediately = 1;
+      parse_and_execute (savestring (trap_command), "trap", SEVAL_NOHIST|SEVAL_RESETLINE);
+    }
+
+  run_unwind_frame ("SIGCHLD trap");
+}
+
+/* Function to call when you want to notify people of changes
+   in job status.  This prints out all jobs which are pending
+   notification to stderr, and marks those printed as already
+   notified, thus making them candidates for cleanup. */
+static void
+notify_of_job_status ()
+{
+  register int job, termsig;
+  char *dir;
+  sigset_t set, oset;
+  WAIT s;
+
+  if (jobs == 0 || js.j_jobslots == 0)
+    return;
+
+  if (old_ttou != 0)
+    {
+      sigemptyset (&set);
+      sigaddset (&set, SIGCHLD);
+      sigaddset (&set, SIGTTOU);
+      sigemptyset (&oset);
+      sigprocmask (SIG_BLOCK, &set, &oset);
+    }
+  else
+    queue_sigchld++;
+
+  /* XXX could use js.j_firstj here */
+  for (job = 0, dir = (char *)NULL; job < js.j_jobslots; job++)
+    {
+      if (jobs[job] && IS_NOTIFIED (job) == 0)
+       {
+         s = raw_job_exit_status (job);
+         termsig = WTERMSIG (s);
+
+         /* POSIX.2 says we have to hang onto the statuses of at most the
+            last CHILD_MAX background processes if the shell is running a
+            script.  If the shell is running a script, either from a file
+            or standard input, don't print anything unless the job was
+            killed by a signal. */
+         if (startup_state == 0 && WIFSIGNALED (s) == 0 &&
+               ((DEADJOB (job) && IS_FOREGROUND (job) == 0) || STOPPED (job)))
+           continue;
+         
+#if 0
+         /* If job control is disabled, don't print the status messages.
+            Mark dead jobs as notified so that they get cleaned up.  If
+            startup_state == 2, we were started to run `-c command', so
+            don't print anything. */
+         if ((job_control == 0 && interactive_shell) || startup_state == 2)
+#else
+         /* If job control is disabled, don't print the status messages.
+            Mark dead jobs as notified so that they get cleaned up.  If
+            startup_state == 2 and subshell_environment has the
+            SUBSHELL_COMSUB bit turned on, we were started to run a command
+            substitution, so don't print anything. */
+         if ((job_control == 0 && interactive_shell) ||
+             (startup_state == 2 && (subshell_environment & SUBSHELL_COMSUB)))
+#endif
+           {
+             /* POSIX.2 compatibility:  if the shell is not interactive,
+                hang onto the job corresponding to the last asynchronous
+                pid until the user has been notified of its status or does
+                a `wait'. */
+             if (DEADJOB (job) && (interactive_shell || (find_last_pid (job, 0) != last_asynchronous_pid)))
+               jobs[job]->flags |= J_NOTIFIED;
+             continue;
+           }
+
+         /* Print info on jobs that are running in the background,
+            and on foreground jobs that were killed by anything
+            except SIGINT (and possibly SIGPIPE). */
+         switch (JOBSTATE (job))
+           {
+           case JDEAD:
+             if (interactive_shell == 0 && termsig && WIFSIGNALED (s) &&
+                 termsig != SIGINT &&
+#if defined (DONT_REPORT_SIGPIPE)
+                 termsig != SIGPIPE &&
+#endif
+                 signal_is_trapped (termsig) == 0)
+               {
+                 /* Don't print `0' for a line number. */
+                 fprintf (stderr, "%s: line %d: ", get_name_for_error (), (line_number == 0) ? 1 : line_number);
+                 pretty_print_job (job, JLIST_NONINTERACTIVE, stderr);
+               }
+             else if (IS_FOREGROUND (job))
+               {
+#if !defined (DONT_REPORT_SIGPIPE)
+                 if (termsig && WIFSIGNALED (s) && termsig != SIGINT)
+#else
+                 if (termsig && WIFSIGNALED (s) && termsig != SIGINT && termsig != SIGPIPE)
+#endif
+                   {
+                     fprintf (stderr, "%s", j_strsignal (termsig));
+
+                     if (WIFCORED (s))
+                       fprintf (stderr, " (core dumped)");
+
+                     fprintf (stderr, "\n");
+                   }
+               }
+             else if (job_control)     /* XXX job control test added */
+               {
+                 if (dir == 0)
+                   dir = current_working_directory ();
+                 pretty_print_job (job, JLIST_STANDARD, stderr);
+                 if (dir && strcmp (dir, jobs[job]->wd) != 0)
+                   fprintf (stderr,
+                            "(wd now: %s)\n", polite_directory_format (dir));
+               }
+
+             jobs[job]->flags |= J_NOTIFIED;
+             break;
+
+           case JSTOPPED:
+             fprintf (stderr, "\n");
+             if (dir == 0)
+               dir = current_working_directory ();
+             pretty_print_job (job, JLIST_STANDARD, stderr);
+             if (dir && (strcmp (dir, jobs[job]->wd) != 0))
+               fprintf (stderr,
+                        "(wd now: %s)\n", polite_directory_format (dir));
+             jobs[job]->flags |= J_NOTIFIED;
+             break;
+
+           case JRUNNING:
+           case JMIXED:
+             break;
+
+           default:
+             programming_error ("notify_of_job_status");
+           }
+       }
+    }
+  if (old_ttou != 0)
+    sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
+  else
+    queue_sigchld--;
+}
+
+/* Initialize the job control mechanism, and set up the tty stuff. */
+int
+initialize_job_control (force)
+     int force;
+{
+  shell_pgrp = getpgid (0);
+
+  if (shell_pgrp == -1)
+    {
+      sys_error ("initialize_job_control: getpgrp failed");
+      exit (1);
+    }
+
+  /* We can only have job control if we are interactive. */
+  if (interactive == 0)
+    {
+      job_control = 0;
+      original_pgrp = NO_PID;
+      shell_tty = fileno (stderr);
+    }
+  else
+    {
+      /* Get our controlling terminal.  If job_control is set, or
+        interactive is set, then this is an interactive shell no
+        matter where fd 2 is directed. */
+      shell_tty = dup (fileno (stderr));       /* fd 2 */
+
+      shell_tty = move_to_high_fd (shell_tty, 1, -1);
+
+      /* Compensate for a bug in systems that compiled the BSD
+        rlogind with DEBUG defined, like NeXT and Alliant. */
+      if (shell_pgrp == 0)
+       {
+         shell_pgrp = getpid ();
+         setpgid (0, shell_pgrp);
+         tcsetpgrp (shell_tty, shell_pgrp);
+       }
+
+      while ((terminal_pgrp = tcgetpgrp (shell_tty)) != -1)
+       {
+         if (shell_pgrp != terminal_pgrp)
+           {
+             SigHandler *ottin;
+
+             ottin = set_signal_handler(SIGTTIN, SIG_DFL);
+             kill (0, SIGTTIN);
+             set_signal_handler (SIGTTIN, ottin);
+             continue;
+           }
+         break;
+       }
+
+      /* Make sure that we are using the new line discipline. */
+      if (set_new_line_discipline (shell_tty) < 0)
+       {
+         sys_error ("initialize_job_control: line discipline");
+         job_control = 0;
+       }
+      else
+       {
+         original_pgrp = shell_pgrp;
+         shell_pgrp = getpid ();
+
+         if ((original_pgrp != shell_pgrp) && (setpgid (0, shell_pgrp) < 0))
+           {
+             sys_error ("initialize_job_control: setpgid");
+             shell_pgrp = original_pgrp;
+           }
+
+         job_control = 1;
+
+         /* If (and only if) we just set our process group to our pid,
+            thereby becoming a process group leader, and the terminal
+            is not in the same process group as our (new) process group,
+            then set the terminal's process group to our (new) process
+            group.  If that fails, set our process group back to what it
+            was originally (so we can still read from the terminal) and
+            turn off job control.  */
+         if (shell_pgrp != original_pgrp && shell_pgrp != terminal_pgrp)
+           {
+             if (give_terminal_to (shell_pgrp, 0) < 0)
+               {
+                 setpgid (0, original_pgrp);
+                 shell_pgrp = original_pgrp;
+                 job_control = 0;
+               }
+           }
+       }
+      if (job_control == 0)
+       internal_error (_("no job control in this shell"));
+    }
+
+  if (shell_tty != fileno (stderr))
+    SET_CLOSE_ON_EXEC (shell_tty);
+
+  set_signal_handler (SIGCHLD, sigchld_handler);
+
+  change_flag ('m', job_control ? '-' : '+');
+
+  if (interactive)
+    get_tty_state ();
+
+  if (js.c_childmax < 0)
+    js.c_childmax = getmaxchild ();
+  if (js.c_childmax < 0)
+    js.c_childmax = DEFAULT_CHILD_MAX;
+
+  return job_control;
+}
+
+#ifdef DEBUG
+void
+debug_print_pgrps ()
+{
+  itrace("original_pgrp = %ld shell_pgrp = %ld terminal_pgrp = %ld",
+        (long)original_pgrp, (long)shell_pgrp, (long)terminal_pgrp);
+  itrace("tcgetpgrp(%d) -> %ld, getpgid(0) -> %ld",
+        shell_tty, (long)tcgetpgrp (shell_tty), (long)getpgid(0));
+}
+#endif
+
+/* Set the line discipline to the best this system has to offer.
+   Return -1 if this is not possible. */
+static int
+set_new_line_discipline (tty)
+     int tty;
+{
+#if defined (NEW_TTY_DRIVER)
+  int ldisc;
+
+  if (ioctl (tty, TIOCGETD, &ldisc) < 0)
+    return (-1);
+
+  if (ldisc != NTTYDISC)
+    {
+      ldisc = NTTYDISC;
+
+      if (ioctl (tty, TIOCSETD, &ldisc) < 0)
+       return (-1);
+    }
+  return (0);
+#endif /* NEW_TTY_DRIVER */
+
+#if defined (TERMIO_TTY_DRIVER)
+#  if defined (TERMIO_LDISC) && (NTTYDISC)
+  if (ioctl (tty, TCGETA, &shell_tty_info) < 0)
+    return (-1);
+
+  if (shell_tty_info.c_line != NTTYDISC)
+    {
+      shell_tty_info.c_line = NTTYDISC;
+      if (ioctl (tty, TCSETAW, &shell_tty_info) < 0)
+       return (-1);
+    }
+#  endif /* TERMIO_LDISC && NTTYDISC */
+  return (0);
+#endif /* TERMIO_TTY_DRIVER */
+
+#if defined (TERMIOS_TTY_DRIVER)
+#  if defined (TERMIOS_LDISC) && defined (NTTYDISC)
+  if (tcgetattr (tty, &shell_tty_info) < 0)
+    return (-1);
+
+  if (shell_tty_info.c_line != NTTYDISC)
+    {
+      shell_tty_info.c_line = NTTYDISC;
+      if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0)
+       return (-1);
+    }
+#  endif /* TERMIOS_LDISC && NTTYDISC */
+  return (0);
+#endif /* TERMIOS_TTY_DRIVER */
+
+#if !defined (NEW_TTY_DRIVER) && !defined (TERMIO_TTY_DRIVER) && !defined (TERMIOS_TTY_DRIVER)
+  return (-1);
+#endif
+}
+
+/* Setup this shell to handle C-C, etc. */
+void
+initialize_job_signals ()
+{
+  if (interactive)
+    {
+      set_signal_handler (SIGINT, sigint_sighandler);
+      set_signal_handler (SIGTSTP, SIG_IGN);
+      set_signal_handler (SIGTTOU, SIG_IGN);
+      set_signal_handler (SIGTTIN, SIG_IGN);
+    }
+  else if (job_control)
+    {
+      old_tstp = set_signal_handler (SIGTSTP, sigstop_sighandler);
+      old_ttin = set_signal_handler (SIGTTIN, sigstop_sighandler);
+      old_ttou = set_signal_handler (SIGTTOU, sigstop_sighandler);
+    }
+  /* Leave these things alone for non-interactive shells without job
+     control. */
+}
+
+/* Here we handle CONT signals. */
+static sighandler
+sigcont_sighandler (sig)
+     int sig;
+{
+  initialize_job_signals ();
+  set_signal_handler (SIGCONT, old_cont);
+  kill (getpid (), SIGCONT);
+
+  SIGRETURN (0);
+}
+
+/* Here we handle stop signals while we are running not as a login shell. */
+static sighandler
+sigstop_sighandler (sig)
+     int sig;
+{
+  set_signal_handler (SIGTSTP, old_tstp);
+  set_signal_handler (SIGTTOU, old_ttou);
+  set_signal_handler (SIGTTIN, old_ttin);
+
+  old_cont = set_signal_handler (SIGCONT, sigcont_sighandler);
+
+  give_terminal_to (shell_pgrp, 0);
+
+  kill (getpid (), sig);
+
+  SIGRETURN (0);
+}
+
+/* Give the terminal to PGRP.  */
+int
+give_terminal_to (pgrp, force)
+     pid_t pgrp;
+     int force;
+{
+  sigset_t set, oset;
+  int r;
+
+  r = 0;
+  if (job_control || force)
+    {
+      sigemptyset (&set);
+      sigaddset (&set, SIGTTOU);
+      sigaddset (&set, SIGTTIN);
+      sigaddset (&set, SIGTSTP);
+      sigaddset (&set, SIGCHLD);
+      sigemptyset (&oset);
+      sigprocmask (SIG_BLOCK, &set, &oset);
+
+      if (tcsetpgrp (shell_tty, pgrp) < 0)
+       {
+         /* Maybe we should print an error message? */
+#if 0
+         sys_error ("tcsetpgrp(%d) failed: pid %ld to pgrp %ld",
+           shell_tty, (long)getpid(), (long)pgrp);
+#endif
+         r = -1;
+       }
+      else
+       terminal_pgrp = pgrp;
+      sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
+    }
+
+  return r;
+}
+
+/* Clear out any jobs in the job array.  This is intended to be used by
+   children of the shell, who should not have any job structures as baggage
+   when they start executing (forking subshells for parenthesized execution
+   and functions with pipes are the two that spring to mind).  If RUNNING_ONLY
+   is nonzero, only running jobs are removed from the table. */
+void
+delete_all_jobs (running_only)
+     int running_only;
+{
+  register int i;
+  sigset_t set, oset;
+
+  BLOCK_CHILD (set, oset);
+
+  /* XXX - need to set j_lastj, j_firstj appropriately if running_only != 0. */
+  if (js.j_jobslots)
+    {
+      js.j_current = js.j_previous = NO_JOB;
+
+      /* XXX could use js.j_firstj here */
+      for (i = 0; i < js.j_jobslots; i++)
+       {
+#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, DEL_WARNSTOPPED);
+       }
+      if (running_only == 0)
+       {
+         free ((char *)jobs);
+         js.j_jobslots = 0;
+         js.j_firstj = js.j_lastj = js.j_njobs = 0;
+       }
+    }
+
+  if (running_only == 0)
+    bgp_clear ();
+
+  UNBLOCK_CHILD (oset);
+}
+
+/* Mark all jobs in the job array so that they don't get a SIGHUP when the
+   shell gets one.  If RUNNING_ONLY is nonzero, mark only running jobs. */
+void
+nohup_all_jobs (running_only)
+     int running_only;
+{
+  register int i;
+  sigset_t set, oset;
+
+  BLOCK_CHILD (set, oset);
+
+  if (js.j_jobslots)
+    {
+      /* XXX could use js.j_firstj here */
+      for (i = 0; i < js.j_jobslots; i++)
+       if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i))))
+         nohup_job (i);
+    }
+
+  UNBLOCK_CHILD (oset);
+}
+
+int
+count_all_jobs ()
+{
+  int i, n;
+  sigset_t set, oset;
+
+  /* This really counts all non-dead jobs. */
+  BLOCK_CHILD (set, oset);
+  /* XXX could use js.j_firstj here */
+  for (i = n = 0; i < js.j_jobslots; i++)
+    {
+#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++;
+    }
+  UNBLOCK_CHILD (oset);
+  return n;
+}
+
+static void
+mark_all_jobs_as_dead ()
+{
+  register int i;
+  sigset_t set, oset;
+
+  if (js.j_jobslots == 0)
+    return;
+
+  BLOCK_CHILD (set, oset);
+
+  /* XXX could use js.j_firstj here */
+  for (i = 0; i < js.j_jobslots; i++)
+    if (jobs[i])
+      {
+       jobs[i]->state = JDEAD;
+       js.j_ndead++;
+      }
+
+  UNBLOCK_CHILD (oset);
+}
+
+/* Mark all dead jobs as notified, so delete_job () cleans them out
+   of the job table properly.  POSIX.2 says we need to save the
+   status of the last CHILD_MAX jobs, so we count the number of dead
+   jobs and mark only enough as notified to save CHILD_MAX statuses. */
+static void
+mark_dead_jobs_as_notified (force)
+     int force;
+{
+  register int i, ndead, ndeadproc;
+  sigset_t set, oset;
+
+  if (js.j_jobslots == 0)
+    return;
+
+  BLOCK_CHILD (set, oset);
+
+  /* If FORCE is non-zero, we don't have to keep CHILD_MAX statuses
+     around; just run through the array. */
+  if (force)
+    {
+    /* XXX could use js.j_firstj here */
+      for (i = 0; i < js.j_jobslots; i++)
+       {
+         if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid)))
+           jobs[i]->flags |= J_NOTIFIED;
+       }
+      UNBLOCK_CHILD (oset);
+      return;
+    }
+
+  /* Mark enough dead jobs as notified to keep CHILD_MAX processes left in the
+     array with the corresponding not marked as notified.  This is a better
+     way to avoid pid aliasing and reuse problems than keeping the POSIX-
+     mandated CHILD_MAX jobs around.  delete_job() takes care of keeping the
+     bgpids list regulated. */
+          
+  /* Count the number of dead jobs */
+  /* XXX could use js.j_firstj here */
+  for (i = ndead = ndeadproc = 0; i < js.j_jobslots; i++)
+    {
+#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))
+       {
+         ndead++;
+         ndeadproc += processes_in_job (i);
+       }
+    }
+
+#ifdef DEBUG
+  if (ndeadproc != js.c_reaped)
+    itrace("mark_dead_jobs_as_notified: ndeadproc (%d) != js.c_reaped (%d)", ndeadproc, js.c_reaped);
+  if (ndead != js.j_ndead)
+    itrace("mark_dead_jobs_as_notified: ndead (%d) != js.j_ndead (%d)", ndead, js.j_ndead);
+#endif
+
+  if (js.c_childmax < 0)
+    js.c_childmax = getmaxchild ();
+  if (js.c_childmax < 0)
+    js.c_childmax = DEFAULT_CHILD_MAX;
+
+  /* Don't do anything if the number of dead processes is less than CHILD_MAX
+     and we're not forcing a cleanup. */
+  if (ndeadproc <= js.c_childmax)
+    {
+      UNBLOCK_CHILD (oset);
+      return;
+    }
+
+#if 0
+itrace("mark_dead_jobs_as_notified: child_max = %d ndead = %d ndeadproc = %d", js.c_childmax, ndead, ndeadproc);
+#endif
+
+  /* Mark enough dead jobs as notified that we keep CHILD_MAX jobs in
+     the list.  This isn't exactly right yet; changes need to be made
+     to stop_pipeline so we don't mark the newer jobs after we've
+     created CHILD_MAX slots in the jobs array.  This needs to be
+     integrated with a way to keep the jobs array from growing without
+     bound.  Maybe we wrap back around to 0 after we reach some max
+     limit, and there are sufficient job slots free (keep track of total
+     size of jobs array (js.j_jobslots) and running count of number of jobs
+     in jobs array.  Then keep a job index corresponding to the `oldest job'
+     and start this loop there, wrapping around as necessary.  In effect,
+     we turn the list into a circular buffer. */
+  /* XXX could use js.j_firstj here */
+  for (i = 0; i < js.j_jobslots; i++)
+    {
+      if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid)))
+       {
+#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
+            statuses.  XXX -- need to check what Posix actually says
+            about keeping statuses. */
+         if ((ndeadproc -= processes_in_job (i)) <= js.c_childmax)
+           break;
+         jobs[i]->flags |= J_NOTIFIED;
+       }
+    }
+
+  UNBLOCK_CHILD (oset);
+}
+
+/* Here to allow other parts of the shell (like the trap stuff) to
+   unfreeze the jobs list. */
+void
+unfreeze_jobs_list ()
+{
+  jobs_list_frozen = 0;
+}
+
+/* Allow or disallow job control to take place.  Returns the old value
+   of job_control. */
+int
+set_job_control (arg)
+     int arg;
+{
+  int old;
+
+  old = job_control;
+  job_control = arg;
+
+  /* If we're turning on job control, reset pipeline_pgrp so make_child will
+     put new child processes into the right pgrp */
+  if (job_control != old && job_control)
+    pipeline_pgrp = 0;
+
+  return (old);
+}
+
+/* Turn off all traces of job control.  This is run by children of the shell
+   which are going to do shellsy things, like wait (), etc. */
+void
+without_job_control ()
+{
+  stop_making_children ();
+  start_pipeline ();
+#if defined (PGRP_PIPE)
+  pipe_close (pgrp_pipe);
+#endif
+  delete_all_jobs (0);
+  set_job_control (0);
+}
+
+/* If this shell is interactive, terminate all stopped jobs and
+   restore the original terminal process group.  This is done
+   before the `exec' builtin calls shell_execve. */
+void
+end_job_control ()
+{
+  if (interactive_shell)               /* XXX - should it be interactive? */
+    {
+      terminate_stopped_jobs ();
+
+      if (original_pgrp >= 0)
+       give_terminal_to (original_pgrp, 1);
+    }
+
+  if (original_pgrp >= 0)
+    setpgid (0, original_pgrp);
+}
+
+/* Restart job control by closing shell tty and reinitializing.  This is
+   called after an exec fails in an interactive shell and we do not exit. */
+void
+restart_job_control ()
+{
+  if (shell_tty != -1)
+    close (shell_tty);
+  initialize_job_control (0);
+}
+
+/* Set the handler to run when the shell receives a SIGCHLD signal. */
+void
+set_sigchld_handler ()
+{
+  set_signal_handler (SIGCHLD, sigchld_handler);
+}
+
+#if defined (PGRP_PIPE)
+/* Read from the read end of a pipe.  This is how the process group leader
+   blocks until all of the processes in a pipeline have been made. */
+static void
+pipe_read (pp)
+     int *pp;
+{
+  char ch;
+
+  if (pp[1] >= 0)
+    {
+      close (pp[1]);
+      pp[1] = -1;
+    }
+
+  if (pp[0] >= 0)
+    {
+      while (read (pp[0], &ch, 1) == -1 && errno == EINTR)
+       ;
+    }
+}
+
+/* Close the read and write ends of PP, an array of file descriptors. */
+static void
+pipe_close (pp)
+     int *pp;
+{
+  if (pp[0] >= 0)
+    close (pp[0]);
+
+  if (pp[1] >= 0)
+    close (pp[1]);
+
+  pp[0] = pp[1] = -1;
+}
+
+/* Functional interface closes our local-to-job-control pipes. */
+void
+close_pgrp_pipe ()
+{
+  pipe_close (pgrp_pipe);
+}
+
+#endif /* PGRP_PIPE */
diff --git a/jobs.c~ b/jobs.c~
index 88ff1d52489d9bfa7e36ff87c0bfc2263661c0d0..fcd146e381c2907ffbd0c03f8fe919e3610a1c9f 100644 (file)
--- a/jobs.c~
+++ b/jobs.c~
@@ -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
index 6f2e2ee2d345271afa81771f6ebc368d0d4d564c..8fcfaeb5033ff73dbf21948d6db90bb563f6476d 100644 (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
diff --git a/lib/readline/doc/rltech.texi~ b/lib/readline/doc/rltech.texi~
new file mode 100644 (file)
index 0000000..6f2e2ee
--- /dev/null
@@ -0,0 +1,2285 @@
+@comment %**start of header (This is for running Texinfo on a region.)
+@setfilename rltech.info
+@comment %**end of header (This is for running Texinfo on a region.)
+@setchapternewpage odd
+
+@ifinfo
+This document describes the GNU Readline Library, a utility for aiding
+in the consistency of user interface across discrete programs that need
+to provide a command line interface.
+
+Copyright (C) 1988-2005 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+pare preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+@end ignore
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end ifinfo
+
+@node Programming with GNU Readline
+@chapter Programming with GNU Readline
+
+This chapter describes the interface between the @sc{gnu} Readline Library and
+other programs.  If you are a programmer, and you wish to include the
+features found in @sc{gnu} Readline
+such as completion, line editing, and interactive history manipulation
+in your own programs, this section is for you.
+
+@menu
+* Basic Behavior::     Using the default behavior of Readline.
+* Custom Functions::   Adding your own functions to Readline.
+* Readline Variables::                 Variables accessible to custom
+                                       functions.
+* Readline Convenience Functions::     Functions which Readline supplies to
+                                       aid in writing your own custom
+                                       functions.
+* Readline Signal Handling::   How Readline behaves when it receives signals.
+* Custom Completers::  Supplanting or supplementing Readline's
+                       completion functions.
+@end menu
+
+@node Basic Behavior
+@section Basic Behavior
+
+Many programs provide a command line interface, such as @code{mail},
+@code{ftp}, and @code{sh}.  For such programs, the default behaviour of
+Readline is sufficient.  This section describes how to use Readline in
+the simplest way possible, perhaps to replace calls in your code to
+@code{gets()} or @code{fgets()}.
+
+@findex readline
+@cindex readline, function
+
+The function @code{readline()} prints a prompt @var{prompt}
+and then reads and returns a single line of text from the user.
+If @var{prompt} is @code{NULL} or the empty string, no prompt is displayed.
+The line @code{readline} returns is allocated with @code{malloc()};
+the caller should @code{free()} the line when it has finished with it.
+The declaration for @code{readline} in ANSI C is
+
+@example
+@code{char *readline (const char *@var{prompt});}
+@end example
+
+@noindent
+So, one might say
+@example
+@code{char *line = readline ("Enter a line: ");}
+@end example
+@noindent
+in order to read a line of text from the user.
+The line returned has the final newline removed, so only the
+text remains.
+
+If @code{readline} encounters an @code{EOF} while reading the line, and the
+line is empty at that point, then @code{(char *)NULL} is returned.
+Otherwise, the line is ended just as if a newline had been typed.
+
+If you want the user to be able to get at the line later, (with
+@key{C-p} for example), you must call @code{add_history()} to save the
+line away in a @dfn{history} list of such lines.
+
+@example
+@code{add_history (line)};
+@end example
+
+@noindent
+For full details on the GNU History Library, see the associated manual.
+
+It is preferable to avoid saving empty lines on the history list, since
+users rarely have a burning need to reuse a blank line.  Here is
+a function which usefully replaces the standard @code{gets()} library
+function, and has the advantage of no static buffer to overflow:
+
+@example
+/* A static variable for holding the line. */
+static char *line_read = (char *)NULL;
+
+/* Read a string, and return a pointer to it.
+   Returns NULL on EOF. */
+char *
+rl_gets ()
+@{
+  /* If the buffer has already been allocated,
+     return the memory to the free pool. */
+  if (line_read)
+    @{
+      free (line_read);
+      line_read = (char *)NULL;
+    @}
+
+  /* Get a line from the user. */
+  line_read = readline ("");
+
+  /* If the line has any text in it,
+     save it on the history. */
+  if (line_read && *line_read)
+    add_history (line_read);
+
+  return (line_read);
+@}
+@end example
+
+This function gives the user the default behaviour of @key{TAB}
+completion: completion on file names.  If you do not want Readline to
+complete on filenames, you can change the binding of the @key{TAB} key
+with @code{rl_bind_key()}.
+
+@example
+@code{int rl_bind_key (int @var{key}, rl_command_func_t *@var{function});}
+@end example
+
+@code{rl_bind_key()} takes two arguments: @var{key} is the character that
+you want to bind, and @var{function} is the address of the function to
+call when @var{key} is pressed.  Binding @key{TAB} to @code{rl_insert()}
+makes @key{TAB} insert itself.
+@code{rl_bind_key()} returns non-zero if @var{key} is not a valid
+ASCII character code (between 0 and 255).
+
+Thus, to disable the default @key{TAB} behavior, the following suffices:
+@example
+@code{rl_bind_key ('\t', rl_insert);}
+@end example
+
+This code should be executed once at the start of your program; you
+might write a function called @code{initialize_readline()} which
+performs this and other desired initializations, such as installing
+custom completers (@pxref{Custom Completers}).
+
+@node Custom Functions
+@section Custom Functions
+
+Readline provides many functions for manipulating the text of
+the line, but it isn't possible to anticipate the needs of all
+programs.  This section describes the various functions and variables
+defined within the Readline library which allow a user program to add
+customized functionality to Readline.
+
+Before declaring any functions that customize Readline's behavior, or
+using any functionality Readline provides in other code, an
+application writer should include the file @code{<readline/readline.h>}
+in any file that uses Readline's features.  Since some of the definitions
+in @code{readline.h} use the @code{stdio} library, the file
+@code{<stdio.h>} should be included before @code{readline.h}.
+
+@code{readline.h} defines a C preprocessor variable that should
+be treated as an integer, @code{RL_READLINE_VERSION}, which may
+be used to conditionally compile application code depending on
+the installed Readline version.  The value is a hexadecimal
+encoding of the major and minor version numbers of the library,
+of the form 0x@var{MMmm}.  @var{MM} is the two-digit major
+version number; @var{mm} is the two-digit minor version number. 
+For Readline 4.2, for example, the value of
+@code{RL_READLINE_VERSION} would be @code{0x0402}. 
+
+@menu
+* Readline Typedefs::  C declarations to make code readable.
+* Function Writing::   Variables and calling conventions.
+@end menu
+
+@node Readline Typedefs
+@subsection Readline Typedefs
+
+For readabilty, we declare a number of new object types, all pointers
+to functions.
+
+The reason for declaring these new types is to make it easier to write
+code describing pointers to C functions with appropriately prototyped
+arguments and return values.
+
+For instance, say we want to declare a variable @var{func} as a pointer
+to a function which takes two @code{int} arguments and returns an
+@code{int} (this is the type of all of the Readline bindable functions).
+Instead of the classic C declaration
+
+@code{int (*func)();}
+
+@noindent
+or the ANSI-C style declaration
+
+@code{int (*func)(int, int);}
+
+@noindent
+we may write
+
+@code{rl_command_func_t *func;}
+
+The full list of function pointer types available is
+
+@table @code
+@item typedef int rl_command_func_t (int, int);
+
+@item typedef char *rl_compentry_func_t (const char *, int);
+
+@item typedef char **rl_completion_func_t (const char *, int, int);
+
+@item typedef char *rl_quote_func_t (char *, int, char *);
+
+@item typedef char *rl_dequote_func_t (char *, int);
+
+@item typedef int rl_compignore_func_t (char **);
+
+@item typedef void rl_compdisp_func_t (char **, int, int);
+
+@item typedef int rl_hook_func_t (void);
+
+@item typedef int rl_getc_func_t (FILE *);
+
+@item typedef int rl_linebuf_func_t (char *, int);
+
+@item typedef int rl_intfunc_t (int);
+@item #define rl_ivoidfunc_t rl_hook_func_t
+@item typedef int rl_icpfunc_t (char *);
+@item typedef int rl_icppfunc_t (char **);
+
+@item typedef void rl_voidfunc_t (void);
+@item typedef void rl_vintfunc_t (int);
+@item typedef void rl_vcpfunc_t (char *);
+@item typedef void rl_vcppfunc_t (char **);
+
+@end table
+
+@node Function Writing
+@subsection Writing a New Function
+
+In order to write new functions for Readline, you need to know the
+calling conventions for keyboard-invoked functions, and the names of the
+variables that describe the current state of the line read so far.
+
+The calling sequence for a command @code{foo} looks like
+
+@example
+@code{int foo (int count, int key)}
+@end example
+
+@noindent
+where @var{count} is the numeric argument (or 1 if defaulted) and
+@var{key} is the key that invoked this function.
+
+It is completely up to the function as to what should be done with the
+numeric argument.  Some functions use it as a repeat count, some
+as a flag, and others to choose alternate behavior (refreshing the current
+line as opposed to refreshing the screen, for example).  Some choose to
+ignore it.  In general, if a
+function uses the numeric argument as a repeat count, it should be able
+to do something useful with both negative and positive arguments.
+At the very least, it should be aware that it can be passed a
+negative argument.
+
+A command function should return 0 if its action completes successfully,
+and a non-zero value if some error occurs.
+This is the convention obeyed by all of the builtin Readline bindable
+command functions.
+
+@node Readline Variables
+@section Readline Variables
+
+These variables are available to function writers.
+
+@deftypevar {char *} rl_line_buffer
+This is the line gathered so far.  You are welcome to modify the
+contents of the line, but see @ref{Allowing Undoing}.  The
+function @code{rl_extend_line_buffer} is available to increase
+the memory allocated to @code{rl_line_buffer}.
+@end deftypevar
+
+@deftypevar int rl_point
+The offset of the current cursor position in @code{rl_line_buffer}
+(the @emph{point}).
+@end deftypevar
+
+@deftypevar int rl_end
+The number of characters present in @code{rl_line_buffer}.  When
+@code{rl_point} is at the end of the line, @code{rl_point} and
+@code{rl_end} are equal.
+@end deftypevar
+
+@deftypevar int rl_mark
+The @var{mark} (saved position) in the current line.  If set, the mark
+and point define a @emph{region}.
+@end deftypevar
+
+@deftypevar int rl_done
+Setting this to a non-zero value causes Readline to return the current
+line immediately.
+@end deftypevar
+
+@deftypevar int rl_num_chars_to_read
+Setting this to a positive value before calling @code{readline()} causes
+Readline to return after accepting that many characters, rather
+than reading up to a character bound to @code{accept-line}.
+@end deftypevar
+
+@deftypevar int rl_pending_input
+Setting this to a value makes it the next keystroke read.  This is a
+way to stuff a single character into the input stream.
+@end deftypevar
+
+@deftypevar int rl_dispatching
+Set to a non-zero value if a function is being called from a key binding;
+zero otherwise.  Application functions can test this to discover whether
+they were called directly or by Readline's dispatching mechanism.
+@end deftypevar
+
+@deftypevar int rl_erase_empty_line
+Setting this to a non-zero value causes Readline to completely erase
+the current line, including any prompt, any time a newline is typed as
+the only character on an otherwise-empty line.  The cursor is moved to
+the beginning of the newly-blank line.
+@end deftypevar
+
+@deftypevar {char *} rl_prompt
+The prompt Readline uses.  This is set from the argument to
+@code{readline()}, and should not be assigned to directly.
+The @code{rl_set_prompt()} function (@pxref{Redisplay}) may
+be used to modify the prompt string after calling @code{readline()}.
+@end deftypevar
+
+@deftypevar int rl_already_prompted
+If an application wishes to display the prompt itself, rather than have
+Readline do it the first time @code{readline()} is called, it should set
+this variable to a non-zero value after displaying the prompt.
+The prompt must also be passed as the argument to @code{readline()} so
+the redisplay functions can update the display properly.
+The calling application is responsible for managing the value; Readline
+never sets it.
+@end deftypevar
+
+@deftypevar {const char *} rl_library_version
+The version number of this revision of the library.
+@end deftypevar
+
+@deftypevar int rl_readline_version
+An integer encoding the current version of the library.  The encoding is
+of the form 0x@var{MMmm}, where @var{MM} is the two-digit major version
+number, and @var{mm} is the two-digit minor version number.
+For example, for Readline-4.2, @code{rl_readline_version} would have the
+value 0x0402.
+@end deftypevar
+
+@deftypevar {int} rl_gnu_readline_p
+Always set to 1, denoting that this is @sc{gnu} readline rather than some
+emulation.
+@end deftypevar
+
+@deftypevar {const char *} rl_terminal_name
+The terminal type, used for initialization.  If not set by the application,
+Readline sets this to the value of the @env{TERM} environment variable
+the first time it is called.
+@end deftypevar
+
+@deftypevar {const char *} rl_readline_name
+This variable is set to a unique name by each application using Readline.
+The value allows conditional parsing of the inputrc file
+(@pxref{Conditional Init Constructs}).
+@end deftypevar
+
+@deftypevar {FILE *} rl_instream
+The stdio stream from which Readline reads input.
+If @code{NULL}, Readline defaults to @var{stdin}.
+@end deftypevar
+
+@deftypevar {FILE *} rl_outstream
+The stdio stream to which Readline performs output.
+If @code{NULL}, Readline defaults to @var{stdout}.
+@end deftypevar
+
+@deftypevar int rl_prefer_env_winsize
+If non-zero, Readline gives values found in the @env{LINES} and
+@env{COLUMNS} environment variables greater precedence than values fetched
+from the kernel when computing the screen dimensions.
+@end deftypevar
+
+@deftypevar {rl_command_func_t *} rl_last_func
+The address of the last command function Readline executed.  May be used to
+test whether or not a function is being executed twice in succession, for
+example.
+@end deftypevar
+
+@deftypevar {rl_hook_func_t *} rl_startup_hook
+If non-zero, this is the address of a function to call just
+before @code{readline} prints the first prompt.
+@end deftypevar
+
+@deftypevar {rl_hook_func_t *} rl_pre_input_hook
+If non-zero, this is the address of a function to call after
+the first prompt has been printed and just before @code{readline}
+starts reading input characters.
+@end deftypevar
+
+@deftypevar {rl_hook_func_t *} rl_event_hook
+If non-zero, this is the address of a function to call periodically
+when Readline is waiting for terminal input.
+By default, this will be called at most ten times a second if there
+is no keyboard input.
+@end deftypevar
+
+@deftypevar {rl_getc_func_t *} rl_getc_function
+If non-zero, Readline will call indirectly through this pointer
+to get a character from the input stream.  By default, it is set to
+@code{rl_getc}, the default Readline character input function
+(@pxref{Character Input}).
+@end deftypevar
+
+@deftypevar {rl_voidfunc_t *} rl_redisplay_function
+If non-zero, Readline will call indirectly through this pointer
+to update the display with the current contents of the editing buffer.
+By default, it is set to @code{rl_redisplay}, the default Readline
+redisplay function (@pxref{Redisplay}).
+@end deftypevar
+
+@deftypevar {rl_vintfunc_t *} rl_prep_term_function
+If non-zero, Readline will call indirectly through this pointer
+to initialize the terminal.  The function takes a single argument, an
+@code{int} flag that says whether or not to use eight-bit characters.
+By default, this is set to @code{rl_prep_terminal}
+(@pxref{Terminal Management}).
+@end deftypevar
+
+@deftypevar {rl_voidfunc_t *} rl_deprep_term_function
+If non-zero, Readline will call indirectly through this pointer
+to reset the terminal.  This function should undo the effects of
+@code{rl_prep_term_function}.
+By default, this is set to @code{rl_deprep_terminal}
+(@pxref{Terminal Management}).
+@end deftypevar
+
+@deftypevar {Keymap} rl_executing_keymap
+This variable is set to the keymap (@pxref{Keymaps}) in which the
+currently executing readline function was found.
+@end deftypevar 
+
+@deftypevar {Keymap} rl_binding_keymap
+This variable is set to the keymap (@pxref{Keymaps}) in which the
+last key binding occurred.
+@end deftypevar 
+
+@deftypevar {char *} rl_executing_macro
+This variable is set to the text of any currently-executing macro.
+@end deftypevar
+
+@deftypevar {int} rl_readline_state
+A variable with bit values that encapsulate the current Readline state.
+A bit is set with the @code{RL_SETSTATE} macro, and unset with the
+@code{RL_UNSETSTATE} macro.  Use the @code{RL_ISSTATE} macro to test
+whether a particular state bit is set.  Current state bits include:
+
+@table @code
+@item RL_STATE_NONE
+Readline has not yet been called, nor has it begun to intialize.
+@item RL_STATE_INITIALIZING
+Readline is initializing its internal data structures.
+@item RL_STATE_INITIALIZED
+Readline has completed its initialization.
+@item RL_STATE_TERMPREPPED
+Readline has modified the terminal modes to do its own input and redisplay.
+@item RL_STATE_READCMD
+Readline is reading a command from the keyboard.
+@item RL_STATE_METANEXT
+Readline is reading more input after reading the meta-prefix character.
+@item RL_STATE_DISPATCHING
+Readline is dispatching to a command.
+@item RL_STATE_MOREINPUT
+Readline is reading more input while executing an editing command.
+@item RL_STATE_ISEARCH
+Readline is performing an incremental history search.
+@item RL_STATE_NSEARCH
+Readline is performing a non-incremental history search.
+@item RL_STATE_SEARCH
+Readline is searching backward or forward through the history for a string.
+@item RL_STATE_NUMERICARG
+Readline is reading a numeric argument.
+@item RL_STATE_MACROINPUT
+Readline is currently getting its input from a previously-defined keyboard
+macro.
+@item RL_STATE_MACRODEF
+Readline is currently reading characters defining a keyboard macro.
+@item RL_STATE_OVERWRITE
+Readline is in overwrite mode.
+@item RL_STATE_COMPLETING
+Readline is performing word completion.
+@item RL_STATE_SIGHANDLER
+Readline is currently executing the readline signal handler.
+@item RL_STATE_UNDOING
+Readline is performing an undo.
+@item RL_STATE_DONE
+Readline has read a key sequence bound to @code{accept-line}
+and is about to return the line to the caller.
+@end table
+
+@end deftypevar
+
+@deftypevar {int} rl_explicit_arg
+Set to a non-zero value if an explicit numeric argument was specified by
+the user.  Only valid in a bindable command function.
+@end deftypevar
+
+@deftypevar {int} rl_numeric_arg
+Set to the value of any numeric argument explicitly specified by the user
+before executing the current Readline function.  Only valid in a bindable
+command function.
+@end deftypevar
+
+@deftypevar {int} rl_editing_mode
+Set to a value denoting Readline's current editing mode.  A value of
+@var{1} means Readline is currently in emacs mode; @var{0}
+means that vi mode is active.
+@end deftypevar
+
+
+@node Readline Convenience Functions
+@section Readline Convenience Functions
+
+@menu
+* Function Naming::    How to give a function you write a name.
+* Keymaps::            Making keymaps.
+* Binding Keys::       Changing Keymaps.
+* Associating Function Names and Bindings::    Translate function names to
+                                               key sequences.
+* Allowing Undoing::   How to make your functions undoable.
+* Redisplay::          Functions to control line display.
+* Modifying Text::     Functions to modify @code{rl_line_buffer}.
+* Character Input::    Functions to read keyboard input.
+* Terminal Management::        Functions to manage terminal settings.
+* Utility Functions::  Generally useful functions and hooks.
+* Miscellaneous Functions::    Functions that don't fall into any category.
+* Alternate Interface::        Using Readline in a `callback' fashion.
+* A Readline Example::         An example Readline function.
+@end menu
+
+@node Function Naming
+@subsection Naming a Function
+
+The user can dynamically change the bindings of keys while using
+Readline.  This is done by representing the function with a descriptive
+name.  The user is able to type the descriptive name when referring to
+the function.  Thus, in an init file, one might find
+
+@example
+Meta-Rubout:   backward-kill-word
+@end example
+
+This binds the keystroke @key{Meta-Rubout} to the function
+@emph{descriptively} named @code{backward-kill-word}.  You, as the
+programmer, should bind the functions you write to descriptive names as
+well.  Readline provides a function for doing that:
+
+@deftypefun int rl_add_defun (const char *name, rl_command_func_t *function, int key)
+Add @var{name} to the list of named functions.  Make @var{function} be
+the function that gets called.  If @var{key} is not -1, then bind it to
+@var{function} using @code{rl_bind_key()}.
+@end deftypefun
+
+Using this function alone is sufficient for most applications.
+It is the recommended way to add a few functions to the default
+functions that Readline has built in.
+If you need to do something other than adding a function to Readline,
+you may need to use the underlying functions described below.
+
+@node Keymaps
+@subsection Selecting a Keymap
+
+Key bindings take place on a @dfn{keymap}.  The keymap is the
+association between the keys that the user types and the functions that
+get run.  You can make your own keymaps, copy existing keymaps, and tell
+Readline which keymap to use.
+
+@deftypefun Keymap rl_make_bare_keymap (void)
+Returns a new, empty keymap.  The space for the keymap is allocated with
+@code{malloc()}; the caller should free it by calling
+@code{rl_discard_keymap()} when done.
+@end deftypefun
+
+@deftypefun Keymap rl_copy_keymap (Keymap map)
+Return a new keymap which is a copy of @var{map}.
+@end deftypefun
+
+@deftypefun Keymap rl_make_keymap (void)
+Return a new keymap with the printing characters bound to rl_insert,
+the lowercase Meta characters bound to run their equivalents, and
+the Meta digits bound to produce numeric arguments.
+@end deftypefun
+
+@deftypefun void rl_discard_keymap (Keymap keymap)
+Free the storage associated with @var{keymap}.
+@end deftypefun
+
+Readline has several internal keymaps.  These functions allow you to
+change which keymap is active.
+
+@deftypefun Keymap rl_get_keymap (void)
+Returns the currently active keymap.
+@end deftypefun
+
+@deftypefun void rl_set_keymap (Keymap keymap)
+Makes @var{keymap} the currently active keymap.
+@end deftypefun
+
+@deftypefun Keymap rl_get_keymap_by_name (const char *name)
+Return the keymap matching @var{name}.  @var{name} is one which would
+be supplied in a @code{set keymap} inputrc line (@pxref{Readline Init File}).
+@end deftypefun
+
+@deftypefun {char *} rl_get_keymap_name (Keymap keymap)
+Return the name matching @var{keymap}.  @var{name} is one which would
+be supplied in a @code{set keymap} inputrc line (@pxref{Readline Init File}).
+@end deftypefun
+
+@node Binding Keys
+@subsection Binding Keys
+
+Key sequences are associate with functions through the keymap.
+Readline has several internal keymaps: @code{emacs_standard_keymap},
+@code{emacs_meta_keymap}, @code{emacs_ctlx_keymap},
+@code{vi_movement_keymap}, and @code{vi_insertion_keymap}.
+@code{emacs_standard_keymap} is the default, and the examples in
+this manual assume that.
+
+Since @code{readline()} installs a set of default key bindings the first
+time it is called, there is always the danger that a custom binding
+installed before the first call to @code{readline()} will be overridden.
+An alternate mechanism is to install custom key bindings in an
+initialization function assigned to the @code{rl_startup_hook} variable
+(@pxref{Readline Variables}).
+
+These functions manage key bindings.
+
+@deftypefun int rl_bind_key (int key, rl_command_func_t *function)
+Binds @var{key} to @var{function} in the currently active keymap.
+Returns non-zero in the case of an invalid @var{key}.
+@end deftypefun
+
+@deftypefun int rl_bind_key_in_map (int key, rl_command_func_t *function, Keymap map)
+Bind @var{key} to @var{function} in @var{map}.
+Returns non-zero in the case of an invalid @var{key}.
+@end deftypefun
+
+@deftypefun int rl_bind_key_if_unbound (int key, rl_command_func_t *function)
+Binds @var{key} to @var{function} if it is not already bound in the
+currently active keymap.
+Returns non-zero in the case of an invalid @var{key} or if @var{key} is
+already bound.
+@end deftypefun
+
+@deftypefun int rl_bind_key_if_unbound_in_map (int key, rl_command_func_t *function, Keymap map)
+Binds @var{key} to @var{function} if it is not already bound in @var{map}.
+Returns non-zero in the case of an invalid @var{key} or if @var{key} is
+already bound.
+@end deftypefun
+
+@deftypefun int rl_unbind_key (int key)
+Bind @var{key} to the null function in the currently active keymap.
+Returns non-zero in case of error.
+@end deftypefun
+
+@deftypefun int rl_unbind_key_in_map (int key, Keymap map)
+Bind @var{key} to the null function in @var{map}.
+Returns non-zero in case of error.
+@end deftypefun
+
+@deftypefun int rl_unbind_function_in_map (rl_command_func_t *function, Keymap map)
+Unbind all keys that execute @var{function} in @var{map}.
+@end deftypefun
+
+@deftypefun int rl_unbind_command_in_map (const char *command, Keymap map)
+Unbind all keys that are bound to @var{command} in @var{map}.
+@end deftypefun
+
+@deftypefun int rl_bind_keyseq (const char *keyseq, rl_command_func_t *function)
+Bind the key sequence represented by the string @var{keyseq} to the function
+@var{function}, beginning in the current keymap.
+This makes new keymaps as necessary.
+The return value is non-zero if @var{keyseq} is invalid.
+@end deftypefun
+
+@deftypefun int rl_bind_keyseq_in_map (const char *keyseq, rl_command_func_t *function, Keymap map)
+Bind the key sequence represented by the string @var{keyseq} to the function
+@var{function}.  This makes new keymaps as necessary.
+Initial bindings are performed in @var{map}.
+The return value is non-zero if @var{keyseq} is invalid.
+@end deftypefun
+
+@deftypefun int rl_set_key (const char *keyseq, rl_command_func_t *function, Keymap map)
+Equivalent to @code{rl_bind_keyseq_in_map}.
+@end deftypefun
+
+@deftypefun int rl_bind_keyseq_if_unbound (const char *keyseq, rl_command_func_t *function)
+Binds @var{keyseq} to @var{function} if it is not already bound in the
+currently active keymap.
+Returns non-zero in the case of an invalid @var{keyseq} or if @var{keyseq} is
+already bound.
+@end deftypefun
+
+@deftypefun int rl_bind_keyseq_if_unbound_in_map (const char *keyseq, rl_command_func_t *function, Keymap map)
+Binds @var{keyseq} to @var{function} if it is not already bound in @var{map}.
+Returns non-zero in the case of an invalid @var{keyseq} or if @var{keyseq} is
+already bound.
+@end deftypefun
+
+@deftypefun int rl_generic_bind (int type, const char *keyseq, char *data, Keymap map)
+Bind the key sequence represented by the string @var{keyseq} to the arbitrary
+pointer @var{data}.  @var{type} says what kind of data is pointed to by
+@var{data}; this can be a function (@code{ISFUNC}), a macro
+(@code{ISMACR}), or a keymap (@code{ISKMAP}).  This makes new keymaps as
+necessary.  The initial keymap in which to do bindings is @var{map}.
+@end deftypefun
+
+@deftypefun int rl_parse_and_bind (char *line)
+Parse @var{line} as if it had been read from the @code{inputrc} file and
+perform any key bindings and variable assignments found
+(@pxref{Readline Init File}).
+@end deftypefun
+
+@deftypefun int rl_read_init_file (const char *filename)
+Read keybindings and variable assignments from @var{filename}
+(@pxref{Readline Init File}).
+@end deftypefun
+
+@node Associating Function Names and Bindings
+@subsection Associating Function Names and Bindings
+
+These functions allow you to find out what keys invoke named functions
+and the functions invoked by a particular key sequence.  You may also
+associate a new function name with an arbitrary function.
+
+@deftypefun {rl_command_func_t *} rl_named_function (const char *name)
+Return the function with name @var{name}.
+@end deftypefun
+
+@deftypefun {rl_command_func_t *} rl_function_of_keyseq (const char *keyseq, Keymap map, int *type)
+Return the function invoked by @var{keyseq} in keymap @var{map}.
+If @var{map} is @code{NULL}, the current keymap is used.  If @var{type} is
+not @code{NULL}, the type of the object is returned in the @code{int} variable
+it points to (one of @code{ISFUNC}, @code{ISKMAP}, or @code{ISMACR}).
+@end deftypefun
+
+@deftypefun {char **} rl_invoking_keyseqs (rl_command_func_t *function)
+Return an array of strings representing the key sequences used to
+invoke @var{function} in the current keymap.
+@end deftypefun
+
+@deftypefun {char **} rl_invoking_keyseqs_in_map (rl_command_func_t *function, Keymap map)
+Return an array of strings representing the key sequences used to
+invoke @var{function} in the keymap @var{map}.
+@end deftypefun
+
+@deftypefun void rl_function_dumper (int readable)
+Print the readline function names and the key sequences currently
+bound to them to @code{rl_outstream}.  If @var{readable} is non-zero,
+the list is formatted in such a way that it can be made part of an
+@code{inputrc} file and re-read.
+@end deftypefun
+
+@deftypefun void rl_list_funmap_names (void)
+Print the names of all bindable Readline functions to @code{rl_outstream}.
+@end deftypefun
+
+@deftypefun {const char **} rl_funmap_names (void)
+Return a NULL terminated array of known function names.  The array is
+sorted.  The array itself is allocated, but not the strings inside.  You
+should @code{free()} the array when you are done, but not the pointers.
+@end deftypefun
+
+@deftypefun int rl_add_funmap_entry (const char *name, rl_command_func_t *function)
+Add @var{name} to the list of bindable Readline command names, and make
+@var{function} the function to be called when @var{name} is invoked.
+@end deftypefun
+
+@node Allowing Undoing
+@subsection Allowing Undoing
+
+Supporting the undo command is a painless thing, and makes your
+functions much more useful.  It is certainly easy to try
+something if you know you can undo it.
+
+If your function simply inserts text once, or deletes text once, and
+uses @code{rl_insert_text()} or @code{rl_delete_text()} to do it, then
+undoing is already done for you automatically.
+
+If you do multiple insertions or multiple deletions, or any combination
+of these operations, you should group them together into one operation.
+This is done with @code{rl_begin_undo_group()} and
+@code{rl_end_undo_group()}.
+
+The types of events that can be undone are:
+
+@smallexample
+enum undo_code @{ UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END @}; 
+@end smallexample
+
+Notice that @code{UNDO_DELETE} means to insert some text, and
+@code{UNDO_INSERT} means to delete some text.  That is, the undo code
+tells what to undo, not how to undo it.  @code{UNDO_BEGIN} and
+@code{UNDO_END} are tags added by @code{rl_begin_undo_group()} and
+@code{rl_end_undo_group()}.
+
+@deftypefun int rl_begin_undo_group (void)
+Begins saving undo information in a group construct.  The undo
+information usually comes from calls to @code{rl_insert_text()} and
+@code{rl_delete_text()}, but could be the result of calls to
+@code{rl_add_undo()}.
+@end deftypefun
+
+@deftypefun int rl_end_undo_group (void)
+Closes the current undo group started with @code{rl_begin_undo_group
+()}.  There should be one call to @code{rl_end_undo_group()}
+for each call to @code{rl_begin_undo_group()}.
+@end deftypefun
+
+@deftypefun void rl_add_undo (enum undo_code what, int start, int end, char *text)
+Remember how to undo an event (according to @var{what}).  The affected
+text runs from @var{start} to @var{end}, and encompasses @var{text}.
+@end deftypefun
+
+@deftypefun void rl_free_undo_list (void)
+Free the existing undo list.
+@end deftypefun
+
+@deftypefun int rl_do_undo (void)
+Undo the first thing on the undo list.  Returns @code{0} if there was
+nothing to undo, non-zero if something was undone.
+@end deftypefun
+
+Finally, if you neither insert nor delete text, but directly modify the
+existing text (e.g., change its case), call @code{rl_modifying()}
+once, just before you modify the text.  You must supply the indices of
+the text range that you are going to modify.
+
+@deftypefun int rl_modifying (int start, int end)
+Tell Readline to save the text between @var{start} and @var{end} as a
+single undo unit.  It is assumed that you will subsequently modify
+that text.
+@end deftypefun
+
+@node Redisplay
+@subsection Redisplay
+
+@deftypefun void rl_redisplay (void)
+Change what's displayed on the screen to reflect the current contents
+of @code{rl_line_buffer}.
+@end deftypefun
+
+@deftypefun int rl_forced_update_display (void)
+Force the line to be updated and redisplayed, whether or not
+Readline thinks the screen display is correct.
+@end deftypefun
+
+@deftypefun int rl_on_new_line (void)
+Tell the update functions that we have moved onto a new (empty) line,
+usually after ouputting a newline.
+@end deftypefun
+
+@deftypefun int rl_on_new_line_with_prompt (void)
+Tell the update functions that we have moved onto a new line, with
+@var{rl_prompt} already displayed.
+This could be used by applications that want to output the prompt string
+themselves, but still need Readline to know the prompt string length for
+redisplay.
+It should be used after setting @var{rl_already_prompted}.
+@end deftypefun
+
+@deftypefun int rl_reset_line_state (void)
+Reset the display state to a clean state and redisplay the current line
+starting on a new line.
+@end deftypefun
+
+@deftypefun int rl_crlf (void)
+Move the cursor to the start of the next screen line.
+@end deftypefun
+
+@deftypefun int rl_show_char (int c)
+Display character @var{c} on @code{rl_outstream}.
+If Readline has not been set to display meta characters directly, this
+will convert meta characters to a meta-prefixed key sequence.
+This is intended for use by applications which wish to do their own
+redisplay.
+@end deftypefun
+
+@deftypefun int rl_message (const char *, @dots{})
+The arguments are a format string as would be supplied to @code{printf},
+possibly containing conversion specifications such as @samp{%d}, and
+any additional arguments necessary to satisfy the conversion specifications.
+The resulting string is displayed in the @dfn{echo area}.  The echo area
+is also used to display numeric arguments and search strings.
+You should call @code{rl_save_prompt} to save the prompt information
+before calling this function.
+@end deftypefun
+
+@deftypefun int rl_clear_message (void)
+Clear the message in the echo area.  If the prompt was saved with a call to
+@code{rl_save_prompt} before the last call to @code{rl_message},
+call @code{rl_restore_prompt} before calling this function.
+@end deftypefun
+
+@deftypefun void rl_save_prompt (void)
+Save the local Readline prompt display state in preparation for
+displaying a new message in the message area with @code{rl_message()}.
+@end deftypefun
+
+@deftypefun void rl_restore_prompt (void)
+Restore the local Readline prompt display state saved by the most
+recent call to @code{rl_save_prompt}.
+if @code{rl_save_prompt} was called to save the prompt before a call
+to @code{rl_message}, this function should be called before the
+corresponding call to @code{rl_clear_message}.
+@end deftypefun
+
+@deftypefun int rl_expand_prompt (char *prompt)
+Expand any special character sequences in @var{prompt} and set up the
+local Readline prompt redisplay variables.
+This function is called by @code{readline()}.  It may also be called to
+expand the primary prompt if the @code{rl_on_new_line_with_prompt()}
+function or @code{rl_already_prompted} variable is used.
+It returns the number of visible characters on the last line of the
+(possibly multi-line) prompt.
+Applications may indicate that the prompt contains characters that take
+up no physical screen space when displayed by bracketing a sequence of
+such characters with the special markers @code{RL_PROMPT_START_IGNORE}
+and @code{RL_PROMPT_END_IGNORE} (declared in @file{readline.h}.  This may
+be used to embed terminal-specific escape sequences in prompts.
+@end deftypefun
+
+@deftypefun int rl_set_prompt (const char *prompt)
+Make Readline use @var{prompt} for subsequent redisplay.  This calls
+@code{rl_expand_prompt()} to expand the prompt and sets @code{rl_prompt}
+to the result.
+@end deftypefun
+
+@node Modifying Text
+@subsection Modifying Text
+
+@deftypefun int rl_insert_text (const char *text)
+Insert @var{text} into the line at the current cursor position.
+Returns the number of characters inserted.
+@end deftypefun
+
+@deftypefun int rl_delete_text (int start, int end)
+Delete the text between @var{start} and @var{end} in the current line.
+Returns the number of characters deleted.
+@end deftypefun
+
+@deftypefun {char *} rl_copy_text (int start, int end)
+Return a copy of the text between @var{start} and @var{end} in
+the current line.
+@end deftypefun
+
+@deftypefun int rl_kill_text (int start, int end)
+Copy the text between @var{start} and @var{end} in the current line
+to the kill ring, appending or prepending to the last kill if the
+last command was a kill command.  The text is deleted.
+If @var{start} is less than @var{end},
+the text is appended, otherwise prepended.  If the last command was
+not a kill, a new kill ring slot is used.
+@end deftypefun
+
+@deftypefun int rl_push_macro_input (char *macro)
+Cause @var{macro} to be inserted into the line, as if it had been invoked
+by a key bound to a macro.  Not especially useful; use
+@code{rl_insert_text()} instead.
+@end deftypefun
+
+@node Character Input
+@subsection Character Input
+
+@deftypefun int rl_read_key (void)
+Return the next character available from Readline's current input stream.
+This handles input inserted into
+the input stream via @var{rl_pending_input} (@pxref{Readline Variables})
+and @code{rl_stuff_char()}, macros, and characters read from the keyboard.
+While waiting for input, this function will call any function assigned to
+the @code{rl_event_hook} variable.
+@end deftypefun
+
+@deftypefun int rl_getc (FILE *stream)
+Return the next character available from @var{stream}, which is assumed to
+be the keyboard.
+@end deftypefun
+
+@deftypefun int rl_stuff_char (int c)
+Insert @var{c} into the Readline input stream.  It will be "read"
+before Readline attempts to read characters from the terminal with
+@code{rl_read_key()}.  Up to 512 characters may be pushed back.
+@code{rl_stuff_char} returns 1 if the character was successfully inserted;
+0 otherwise.
+@end deftypefun
+
+@deftypefun int rl_execute_next (int c)
+Make @var{c} be the next command to be executed when @code{rl_read_key()}
+is called.  This sets @var{rl_pending_input}.
+@end deftypefun
+
+@deftypefun int rl_clear_pending_input (void)
+Unset @var{rl_pending_input}, effectively negating the effect of any
+previous call to @code{rl_execute_next()}.  This works only if the
+pending input has not already been read with @code{rl_read_key()}.
+@end deftypefun
+
+@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.
+@end deftypefun
+
+@node Terminal Management
+@subsection Terminal Management
+
+@deftypefun void rl_prep_terminal (int meta_flag)
+Modify the terminal settings for Readline's use, so @code{readline()}
+can read a single character at a time from the keyboard.
+The @var{meta_flag} argument should be non-zero if Readline should
+read eight-bit input.
+@end deftypefun
+
+@deftypefun void rl_deprep_terminal (void)
+Undo the effects of @code{rl_prep_terminal()}, leaving the terminal in
+the state in which it was before the most recent call to
+@code{rl_prep_terminal()}.
+@end deftypefun
+
+@deftypefun void rl_tty_set_default_bindings (Keymap kmap)
+Read the operating system's terminal editing characters (as would be
+displayed by @code{stty}) to their Readline equivalents.
+The bindings are performed in @var{kmap}.
+@end deftypefun
+
+@deftypefun void rl_tty_unset_default_bindings (Keymap kmap)
+Reset the bindings manipulated by @code{rl_tty_set_default_bindings} so
+that the terminal editing characters are bound to @code{rl_insert}.
+The bindings are performed in @var{kmap}.
+@end deftypefun
+
+@deftypefun int rl_reset_terminal (const char *terminal_name)
+Reinitialize Readline's idea of the terminal settings using
+@var{terminal_name} as the terminal type (e.g., @code{vt100}).
+If @var{terminal_name} is @code{NULL}, the value of the @code{TERM}
+environment variable is used.
+@end deftypefun
+
+@node Utility Functions
+@subsection Utility Functions
+
+@deftypefun void rl_replace_line (const char *text, int clear_undo)
+Replace the contents of @code{rl_line_buffer} with @var{text}.
+The point and mark are preserved, if possible.
+If @var{clear_undo} is non-zero, the undo list associated with the
+current line is cleared.
+@end deftypefun
+
+@deftypefun int rl_extend_line_buffer (int len)
+Ensure that @code{rl_line_buffer} has enough space to hold @var{len}
+characters, possibly reallocating it if necessary.
+@end deftypefun
+
+@deftypefun int rl_initialize (void)
+Initialize or re-initialize Readline's internal state.
+It's not strictly necessary to call this; @code{readline()} calls it before
+reading any input.
+@end deftypefun
+
+@deftypefun int rl_ding (void)
+Ring the terminal bell, obeying the setting of @code{bell-style}.
+@end deftypefun
+
+@deftypefun int rl_alphabetic (int c)
+Return 1 if @var{c} is an alphabetic character.
+@end deftypefun
+
+@deftypefun void rl_display_match_list (char **matches, int len, int max)
+A convenience function for displaying a list of strings in
+columnar format on Readline's output stream.  @code{matches} is the list
+of strings, in argv format, such as a list of completion matches.
+@code{len} is the number of strings in @code{matches}, and @code{max}
+is the length of the longest string in @code{matches}.  This function uses
+the setting of @code{print-completions-horizontally} to select how the
+matches are displayed (@pxref{Readline Init File Syntax}).
+@end deftypefun
+
+The following are implemented as macros, defined in @code{chardefs.h}.
+Applications should refrain from using them.
+
+@deftypefun int _rl_uppercase_p (int c)
+Return 1 if @var{c} is an uppercase alphabetic character.
+@end deftypefun
+
+@deftypefun int _rl_lowercase_p (int c)
+Return 1 if @var{c} is a lowercase alphabetic character.
+@end deftypefun
+
+@deftypefun int _rl_digit_p (int c)
+Return 1 if @var{c} is a numeric character.
+@end deftypefun
+
+@deftypefun int _rl_to_upper (int c)
+If @var{c} is a lowercase alphabetic character, return the corresponding
+uppercase character.
+@end deftypefun
+
+@deftypefun int _rl_to_lower (int c)
+If @var{c} is an uppercase alphabetic character, return the corresponding
+lowercase character.
+@end deftypefun
+
+@deftypefun int _rl_digit_value (int c)
+If @var{c} is a number, return the value it represents.
+@end deftypefun
+
+@node Miscellaneous Functions
+@subsection Miscellaneous Functions
+
+@deftypefun int rl_macro_bind (const char *keyseq, const char *macro, Keymap map)
+Bind the key sequence @var{keyseq} to invoke the macro @var{macro}.
+The binding is performed in @var{map}.  When @var{keyseq} is invoked, the
+@var{macro} will be inserted into the line.  This function is deprecated;
+use @code{rl_generic_bind()} instead.
+@end deftypefun
+
+@deftypefun void rl_macro_dumper (int readable)
+Print the key sequences bound to macros and their values, using
+the current keymap, to @code{rl_outstream}.
+If @var{readable} is non-zero, the list is formatted in such a way
+that it can be made part of an @code{inputrc} file and re-read.
+@end deftypefun
+
+@deftypefun int rl_variable_bind (const char *variable, const char *value)
+Make the Readline variable @var{variable} have @var{value}.
+This behaves as if the readline command
+@samp{set @var{variable} @var{value}} had been executed in an @code{inputrc}
+file (@pxref{Readline Init File Syntax}).
+@end deftypefun
+
+@deftypefun {char *} rl_variable_value (const char *variable)
+Return a string representing the value of the Readline variable @var{variable}.
+For boolean variables, this string is either @samp{on} or @samp{off}.
+@end deftypefun
+
+@deftypefun void rl_variable_dumper (int readable)
+Print the readline variable names and their current values
+to @code{rl_outstream}.
+If @var{readable} is non-zero, the list is formatted in such a way
+that it can be made part of an @code{inputrc} file and re-read.
+@end deftypefun
+
+@deftypefun int rl_set_paren_blink_timeout (int u)
+Set the time interval (in microseconds) that Readline waits when showing
+a balancing character when @code{blink-matching-paren} has been enabled.
+@end deftypefun
+
+@deftypefun {char *} rl_get_termcap (const char *cap)
+Retrieve the string value of the termcap capability @var{cap}.
+Readline fetches the termcap entry for the current terminal name and
+uses those capabilities to move around the screen line and perform other
+terminal-specific operations, like erasing a line.  Readline does not
+use all of a terminal's capabilities, and this function will return
+values for only those capabilities Readline uses.
+@end deftypefun
+
+@node Alternate Interface
+@subsection Alternate Interface
+
+An alternate interface is available to plain @code{readline()}.  Some
+applications need to interleave keyboard I/O with file, device, or
+window system I/O, typically by using a main loop to @code{select()}
+on various file descriptors.  To accomodate this need, readline can
+also be invoked as a `callback' function from an event loop.  There
+are functions available to make this easy.
+
+@deftypefun void rl_callback_handler_install (const char *prompt, rl_vcpfunc_t *lhandler)
+Set up the terminal for readline I/O and display the initial
+expanded value of @var{prompt}.  Save the value of @var{lhandler} to
+use as a function to call when a complete line of input has been entered.
+The function takes the text of the line as an argument.
+@end deftypefun
+
+@deftypefun void rl_callback_read_char (void)
+Whenever an application determines that keyboard input is available, it
+should call @code{rl_callback_read_char()}, which will read the next
+character from the current input source.
+If that character completes the line, @code{rl_callback_read_char} will
+invoke the @var{lhandler} function saved by @code{rl_callback_handler_install}
+to process the line.
+Before calling the @var{lhandler} function, the terminal settings are
+reset to the values they had before calling
+@code{rl_callback_handler_install}.
+If the @var{lhandler} function returns,
+the terminal settings are modified for Readline's use again.
+@code{EOF} is  indicated by calling @var{lhandler} with a
+@code{NULL} line.
+@end deftypefun
+
+@deftypefun void rl_callback_handler_remove (void)
+Restore the terminal to its initial state and remove the line handler.
+This may be called from within a callback as well as independently.
+If the @var{lhandler} installed by @code{rl_callback_handler_install}
+does not exit the program, either this function or the function referred
+to by the value of @code{rl_deprep_term_function} should be called before
+the program exits to reset the terminal settings.
+@end deftypefun
+
+@node A Readline Example
+@subsection A Readline Example
+
+Here is a function which changes lowercase characters to their uppercase
+equivalents, and uppercase characters to lowercase.  If
+this function was bound to @samp{M-c}, then typing @samp{M-c} would
+change the case of the character under point.  Typing @samp{M-1 0 M-c}
+would change the case of the following 10 characters, leaving the cursor on
+the last character changed.
+
+@example
+/* Invert the case of the COUNT following characters. */
+int
+invert_case_line (count, key)
+     int count, key;
+@{
+  register int start, end, i;
+
+  start = rl_point;
+
+  if (rl_point >= rl_end)
+    return (0);
+
+  if (count < 0)
+    @{
+      direction = -1;
+      count = -count;
+    @}
+  else
+    direction = 1;
+      
+  /* Find the end of the range to modify. */
+  end = start + (count * direction);
+
+  /* Force it to be within range. */
+  if (end > rl_end)
+    end = rl_end;
+  else if (end < 0)
+    end = 0;
+
+  if (start == end)
+    return (0);
+
+  if (start > end)
+    @{
+      int temp = start;
+      start = end;
+      end = temp;
+    @}
+
+  /* Tell readline that we are modifying the line,
+     so it will save the undo information. */
+  rl_modifying (start, end);
+
+  for (i = start; i != end; i++)
+    @{
+      if (_rl_uppercase_p (rl_line_buffer[i]))
+        rl_line_buffer[i] = _rl_to_lower (rl_line_buffer[i]);
+      else if (_rl_lowercase_p (rl_line_buffer[i]))
+        rl_line_buffer[i] = _rl_to_upper (rl_line_buffer[i]);
+    @}
+  /* Move point to on top of the last character changed. */
+  rl_point = (direction == 1) ? end - 1 : start;
+  return (0);
+@}
+@end example
+
+@node Readline Signal Handling
+@section Readline Signal Handling
+
+Signals are asynchronous events sent to a process by the Unix kernel,
+sometimes on behalf of another process.  They are intended to indicate
+exceptional events, like a user pressing the interrupt key on his terminal,
+or a network connection being broken.  There is a class of signals that can
+be sent to the process currently reading input from the keyboard.  Since
+Readline changes the terminal attributes when it is called, it needs to
+perform special processing when such a signal is received in order to
+restore the terminal to a sane state, or provide application writers with
+functions to do so manually. 
+
+Readline contains an internal signal handler that is installed for a
+number of signals (@code{SIGINT}, @code{SIGQUIT}, @code{SIGTERM},
+@code{SIGALRM}, @code{SIGTSTP}, @code{SIGTTIN}, and @code{SIGTTOU}).
+When one of these signals is received, the signal handler
+will reset the terminal attributes to those that were in effect before
+@code{readline()} was called, reset the signal handling to what it was
+before @code{readline()} was called, and resend the signal to the calling
+application.
+If and when the calling application's signal handler returns, Readline
+will reinitialize the terminal and continue to accept input.
+When a @code{SIGINT} is received, the Readline signal handler performs
+some additional work, which will cause any partially-entered line to be
+aborted (see the description of @code{rl_free_line_state()} below).
+
+There is an additional Readline signal handler, for @code{SIGWINCH}, which
+the kernel sends to a process whenever the terminal's size changes (for
+example, if a user resizes an @code{xterm}).  The Readline @code{SIGWINCH}
+handler updates Readline's internal screen size information, and then calls
+any @code{SIGWINCH} signal handler the calling application has installed. 
+Readline calls the application's @code{SIGWINCH} signal handler without
+resetting the terminal to its original state.  If the application's signal
+handler does more than update its idea of the terminal size and return (for
+example, a @code{longjmp} back to a main processing loop), it @emph{must}
+call @code{rl_cleanup_after_signal()} (described below), to restore the
+terminal state. 
+
+Readline provides two variables that allow application writers to
+control whether or not it will catch certain signals and act on them
+when they are received.  It is important that applications change the
+values of these variables only when calling @code{readline()}, not in
+a signal handler, so Readline's internal signal state is not corrupted.
+
+@deftypevar int rl_catch_signals
+If this variable is non-zero, Readline will install signal handlers for
+@code{SIGINT}, @code{SIGQUIT}, @code{SIGTERM}, @code{SIGALRM},
+@code{SIGTSTP}, @code{SIGTTIN}, and @code{SIGTTOU}.
+
+The default value of @code{rl_catch_signals} is 1.
+@end deftypevar
+
+@deftypevar int rl_catch_sigwinch
+If this variable is non-zero, Readline will install a signal handler for
+@code{SIGWINCH}.
+
+The default value of @code{rl_catch_sigwinch} is 1.
+@end deftypevar
+
+If an application does not wish to have Readline catch any signals, or
+to handle signals other than those Readline catches (@code{SIGHUP},
+for example), 
+Readline provides convenience functions to do the necessary terminal
+and internal state cleanup upon receipt of a signal.
+
+@deftypefun void rl_cleanup_after_signal (void)
+This function will reset the state of the terminal to what it was before
+@code{readline()} was called, and remove the Readline signal handlers for
+all signals, depending on the values of @code{rl_catch_signals} and
+@code{rl_catch_sigwinch}.
+@end deftypefun
+
+@deftypefun void rl_free_line_state (void)
+This will free any partial state associated with the current input line
+(undo information, any partial history entry, any partially-entered
+keyboard macro, and any partially-entered numeric argument).  This
+should be called before @code{rl_cleanup_after_signal()}.  The
+Readline signal handler for @code{SIGINT} calls this to abort the
+current input line.
+@end deftypefun
+
+@deftypefun void rl_reset_after_signal (void)
+This will reinitialize the terminal and reinstall any Readline signal
+handlers, depending on the values of @code{rl_catch_signals} and
+@code{rl_catch_sigwinch}.
+@end deftypefun
+
+If an application does not wish Readline to catch @code{SIGWINCH}, it may
+call @code{rl_resize_terminal()} or @code{rl_set_screen_size()} to force
+Readline to update its idea of the terminal size when a @code{SIGWINCH}
+is received.
+
+@deftypefun void rl_resize_terminal (void)
+Update Readline's internal screen size by reading values from the kernel.
+@end deftypefun
+
+@deftypefun void rl_set_screen_size (int rows, int cols)
+Set Readline's idea of the terminal size to @var{rows} rows and
+@var{cols} columns.  If either @var{rows} or @var{columns} is less than
+or equal to 0, Readline's idea of that terminal dimension is unchanged.
+@end deftypefun
+
+If an application does not want to install a @code{SIGWINCH} handler, but
+is still interested in the screen dimensions, Readline's idea of the screen
+size may be queried.
+
+@deftypefun void rl_get_screen_size (int *rows, int *cols)
+Return Readline's idea of the terminal's size in the
+variables pointed to by the arguments.
+@end deftypefun
+
+@deftypefun void rl_reset_screen_size (void)
+Cause Readline to reobtain the screen size and recalculate its dimensions.
+@end deftypefun
+
+The following functions install and remove Readline's signal handlers.
+
+@deftypefun int rl_set_signals (void)
+Install Readline's signal handler for @code{SIGINT}, @code{SIGQUIT},
+@code{SIGTERM}, @code{SIGALRM}, @code{SIGTSTP}, @code{SIGTTIN},
+@code{SIGTTOU}, and @code{SIGWINCH}, depending on the values of
+@code{rl_catch_signals} and @code{rl_catch_sigwinch}.
+@end deftypefun
+
+@deftypefun int rl_clear_signals (void)
+Remove all of the Readline signal handlers installed by
+@code{rl_set_signals()}.
+@end deftypefun
+
+@node Custom Completers
+@section Custom Completers
+@cindex application-specific completion functions
+
+Typically, a program that reads commands from the user has a way of
+disambiguating commands and data.  If your program is one of these, then
+it can provide completion for commands, data, or both.
+The following sections describe how your program and Readline
+cooperate to provide this service.
+
+@menu
+* How Completing Works::       The logic used to do completion.
+* Completion Functions::       Functions provided by Readline.
+* Completion Variables::       Variables which control completion.
+* A Short Completion Example:: An example of writing completer subroutines.
+@end menu
+
+@node How Completing Works
+@subsection How Completing Works
+
+In order to complete some text, the full list of possible completions
+must be available.  That is, it is not possible to accurately
+expand a partial word without knowing all of the possible words
+which make sense in that context.  The Readline library provides
+the user interface to completion, and two of the most common
+completion functions:  filename and username.  For completing other types
+of text, you must write your own completion function.  This section
+describes exactly what such functions must do, and provides an example.
+
+There are three major functions used to perform completion:
+
+@enumerate
+@item
+The user-interface function @code{rl_complete()}.  This function is
+called with the same arguments as other bindable Readline functions:
+@var{count} and @var{invoking_key}.
+It isolates the word to be completed and calls
+@code{rl_completion_matches()} to generate a list of possible completions.
+It then either lists the possible completions, inserts the possible
+completions, or actually performs the
+completion, depending on which behavior is desired.
+
+@item
+The internal function @code{rl_completion_matches()} uses an
+application-supplied @dfn{generator} function to generate the list of
+possible matches, and then returns the array of these matches.
+The caller should place the address of its generator function in
+@code{rl_completion_entry_function}.
+
+@item
+The generator function is called repeatedly from
+@code{rl_completion_matches()}, returning a string each time.  The
+arguments to the generator function are @var{text} and @var{state}.
+@var{text} is the partial word to be completed.  @var{state} is zero the
+first time the function is called, allowing the generator to perform
+any necessary initialization, and a positive non-zero integer for
+each subsequent call.  The generator function returns
+@code{(char *)NULL} to inform @code{rl_completion_matches()} that there are
+no more possibilities left.  Usually the generator function computes the
+list of possible completions when @var{state} is zero, and returns them
+one at a time on subsequent calls.  Each string the generator function
+returns as a match must be allocated with @code{malloc()}; Readline
+frees the strings when it has finished with them.
+Such a generator function is referred to as an
+@dfn{application-specific completion function}.
+
+@end enumerate
+
+@deftypefun int rl_complete (int ignore, int invoking_key)
+Complete the word at or before point.  You have supplied the function
+that does the initial simple matching selection algorithm (see
+@code{rl_completion_matches()}).  The default is to do filename completion.
+@end deftypefun
+
+@deftypevar {rl_compentry_func_t *} rl_completion_entry_function
+This is a pointer to the generator function for
+@code{rl_completion_matches()}.
+If the value of @code{rl_completion_entry_function} is
+@code{NULL} then the default filename generator
+function, @code{rl_filename_completion_function()}, is used.
+An @dfn{application-specific completion function} is a function whose
+address is assigned to @code{rl_completion_entry_function} and whose
+return values are used to  generate possible completions.
+@end deftypevar
+
+@node Completion Functions
+@subsection Completion Functions
+
+Here is the complete list of callable completion functions present in
+Readline.
+
+@deftypefun int rl_complete_internal (int what_to_do)
+Complete the word at or before point.  @var{what_to_do} says what to do
+with the completion.  A value of @samp{?} means list the possible
+completions.  @samp{TAB} means do standard completion.  @samp{*} means
+insert all of the possible completions.  @samp{!} means to display
+all of the possible completions, if there is more than one, as well as
+performing partial completion.  @samp{@@} is similar to @samp{!}, but
+possible completions are not listed if the possible completions share
+a common prefix.
+@end deftypefun
+
+@deftypefun int rl_complete (int ignore, int invoking_key)
+Complete the word at or before point.  You have supplied the function
+that does the initial simple matching selection algorithm (see
+@code{rl_completion_matches()} and @code{rl_completion_entry_function}).
+The default is to do filename
+completion.  This calls @code{rl_complete_internal()} with an
+argument depending on @var{invoking_key}.
+@end deftypefun
+
+@deftypefun int rl_possible_completions (int count, int invoking_key)
+List the possible completions.  See description of @code{rl_complete
+()}.  This calls @code{rl_complete_internal()} with an argument of
+@samp{?}.
+@end deftypefun
+
+@deftypefun int rl_insert_completions (int count, int invoking_key)
+Insert the list of possible completions into the line, deleting the
+partially-completed word.  See description of @code{rl_complete()}.
+This calls @code{rl_complete_internal()} with an argument of @samp{*}.
+@end deftypefun
+
+@deftypefun int rl_completion_mode (rl_command_func_t *cfunc)
+Returns the apppriate value to pass to @code{rl_complete_internal()}
+depending on whether @var{cfunc} was called twice in succession and
+the values of the @code{show-all-if-ambiguous} and
+@code{show-all-if-unmodified} variables.
+Application-specific completion functions may use this function to present
+the same interface as @code{rl_complete()}.
+@end deftypefun
+
+@deftypefun {char **} rl_completion_matches (const char *text, rl_compentry_func_t *entry_func)
+Returns an array of strings which is a list of completions for
+@var{text}.  If there are no completions, returns @code{NULL}.
+The first entry in the returned array is the substitution for @var{text}.
+The remaining entries are the possible completions.  The array is
+terminated with a @code{NULL} pointer.
+
+@var{entry_func} is a function of two args, and returns a
+@code{char *}.  The first argument is @var{text}.  The second is a
+state argument; it is zero on the first call, and non-zero on subsequent
+calls.  @var{entry_func} returns a @code{NULL}  pointer to the caller
+when there are no more matches.
+@end deftypefun
+
+@deftypefun {char *} rl_filename_completion_function (const char *text, int state)
+A generator function for filename completion in the general case.
+@var{text} is a partial filename.
+The Bash source is a useful reference for writing application-specific
+completion functions (the Bash completion functions call this and other
+Readline functions).
+@end deftypefun
+
+@deftypefun {char *} rl_username_completion_function (const char *text, int state)
+A completion generator for usernames.  @var{text} contains a partial
+username preceded by a random character (usually @samp{~}).  As with all
+completion generators, @var{state} is zero on the first call and non-zero
+for subsequent calls.
+@end deftypefun
+
+@node Completion Variables
+@subsection Completion Variables
+
+@deftypevar {rl_compentry_func_t *} rl_completion_entry_function
+A pointer to the generator function for @code{rl_completion_matches()}.
+@code{NULL} means to use @code{rl_filename_completion_function()},
+the default filename completer.
+@end deftypevar
+
+@deftypevar {rl_completion_func_t *} rl_attempted_completion_function
+A pointer to an alternative function to create matches.
+The function is called with @var{text}, @var{start}, and @var{end}.
+@var{start} and @var{end} are indices in @code{rl_line_buffer} defining
+the boundaries of @var{text}, which is a character string.
+If this function exists and returns @code{NULL}, or if this variable is
+set to @code{NULL}, then @code{rl_complete()} will call the value of
+@code{rl_completion_entry_function} to generate matches, otherwise the
+array of strings returned will be used.
+If this function sets the @code{rl_attempted_completion_over}
+variable to a non-zero value, Readline will not perform its default
+completion even if this function returns no matches.
+@end deftypevar
+
+@deftypevar {rl_quote_func_t *} rl_filename_quoting_function
+A pointer to a function that will quote a filename in an
+application-specific fashion.  This is called if filename completion is being
+attempted and one of the characters in @code{rl_filename_quote_characters}
+appears in a completed filename.  The function is called with
+@var{text}, @var{match_type}, and @var{quote_pointer}.  The @var{text}
+is the filename to be quoted.  The @var{match_type} is either
+@code{SINGLE_MATCH}, if there is only one completion match, or
+@code{MULT_MATCH}.  Some functions use this to decide whether or not to
+insert a closing quote character.  The @var{quote_pointer} is a pointer
+to any opening quote character the user typed.  Some functions choose
+to reset this character.
+@end deftypevar
+
+@deftypevar {rl_dequote_func_t *} rl_filename_dequoting_function
+A pointer to a function that will remove application-specific quoting
+characters from a filename before completion is attempted, so those
+characters do not interfere with matching the text against names in
+the filesystem.  It is called with @var{text}, the text of the word
+to be dequoted, and @var{quote_char}, which is the quoting character 
+that delimits the filename (usually @samp{'} or @samp{"}).  If
+@var{quote_char} is zero, the filename was not in an embedded string.
+@end deftypevar
+
+@deftypevar {rl_linebuf_func_t *} rl_char_is_quoted_p
+A pointer to a function to call that determines whether or not a specific
+character in the line buffer is quoted, according to whatever quoting
+mechanism the program calling Readline uses.  The function is called with
+two arguments: @var{text}, the text of the line, and @var{index}, the
+index of the character in the line.  It is used to decide whether a
+character found in @code{rl_completer_word_break_characters} should be
+used to break words for the completer.
+@end deftypevar
+
+@deftypevar {rl_compignore_func_t *} rl_ignore_some_completions_function
+This function, if defined, is called by the completer when real filename
+completion is done, after all the matching names have been generated.
+It is passed a @code{NULL} terminated array of matches.
+The first element (@code{matches[0]}) is the
+maximal substring common to all matches. This function can
+re-arrange the list of matches as required, but each element deleted
+from the array must be freed.
+@end deftypevar
+
+@deftypevar {rl_icppfunc_t *} rl_directory_completion_hook
+This function, if defined, is allowed to modify the directory portion
+of filenames Readline completes.  It is called with the address of a
+string (the current directory name) as an argument, and may modify that string.
+If the string is replaced with a new string, the old value should be freed.
+Any modified directory name should have a trailing slash.
+The modified value will be displayed as part of the completion, replacing
+the directory portion of the pathname the user typed.
+It returns an integer that should be non-zero if the function modifies
+its directory argument.
+It could be used to expand symbolic links or shell variables in pathnames.
+@end deftypevar
+
+@deftypevar {rl_compdisp_func_t *} rl_completion_display_matches_hook
+If non-zero, then this is the address of a function to call when
+completing a word would normally display the list of possible matches.
+This function is called in lieu of Readline displaying the list.
+It takes three arguments:
+(@code{char **}@var{matches}, @code{int} @var{num_matches}, @code{int} @var{max_length})
+where @var{matches} is the array of matching strings,
+@var{num_matches} is the number of strings in that array, and
+@var{max_length} is the length of the longest string in that array.
+Readline provides a convenience function, @code{rl_display_match_list},
+that takes care of doing the display to Readline's output stream.  That
+function may be called from this hook.
+@end deftypevar
+
+@deftypevar {const char *} rl_basic_word_break_characters
+The basic list of characters that signal a break between words for the
+completer routine.  The default value of this variable is the characters
+which break words for completion in Bash:
+@code{" \t\n\"\\'`@@$><=;|&@{("}.
+@end deftypevar
+
+@deftypevar {const char *} rl_basic_quote_characters
+A list of quote characters which can cause a word break.
+@end deftypevar
+
+@deftypevar {const char *} rl_completer_word_break_characters
+The list of characters that signal a break between words for
+@code{rl_complete_internal()}.  The default list is the value of
+@code{rl_basic_word_break_characters}.
+@end deftypevar
+
+@deftypevar {rl_cpvfunc_t *} rl_completion_word_break_hook
+If non-zero, this is the address of a function to call when Readline is
+deciding where to separate words for word completion.  It should return
+a character string like @code{rl_completer_word_break_characters} to be
+used to perform the current completion.  The function may choose to set
+@code{rl_completer_word_break_characters} itself.  If the function
+returns @code{NULL}, @code{rl_completer_word_break_characters} is used.
+@end deftypevar
+
+@deftypevar {const char *} rl_completer_quote_characters
+A list of characters which can be used to quote a substring of the line.
+Completion occurs on the entire substring, and within the substring
+@code{rl_completer_word_break_characters} are treated as any other character,
+unless they also appear within this list.
+@end deftypevar
+
+@deftypevar {const char *} rl_filename_quote_characters
+A list of characters that cause a filename to be quoted by the completer
+when they appear in a completed filename.  The default is the null string.
+@end deftypevar
+
+@deftypevar {const char *} rl_special_prefixes
+The list of characters that are word break characters, but should be
+left in @var{text} when it is passed to the completion function.
+Programs can use this to help determine what kind of completing to do.
+For instance, Bash sets this variable to "$@@" so that it can complete
+shell variables and hostnames.
+@end deftypevar
+
+@deftypevar int rl_completion_query_items
+Up to this many items will be displayed in response to a
+possible-completions call.  After that, readline asks the user if she is sure
+she wants to see them all.  The default value is 100.  A negative value 
+indicates that Readline should never ask the user.
+@end deftypevar
+
+@deftypevar {int} rl_completion_append_character
+When a single completion alternative matches at the end of the command
+line, this character is appended to the inserted completion text.  The
+default is a space character (@samp{ }).  Setting this to the null
+character (@samp{\0}) prevents anything being appended automatically.
+This can be changed in application-specific completion functions to
+provide the ``most sensible word separator character'' according to
+an application-specific command line syntax specification.
+@end deftypevar
+
+@deftypevar int rl_completion_suppress_append
+If non-zero, @var{rl_completion_append_character} is not appended to
+matches at the end of the command line, as described above.
+It is set to 0 before any application-specific completion function
+is called, and may only be changed within such a function.
+@end deftypevar
+
+@deftypevar int rl_completion_quote_character
+When Readline is completing quoted text, as delimited by one of the
+characters in @var{rl_completer_quote_characters}, it sets this variable
+to the quoting character found.
+This is set before any application-specific completion function is called.
+@end deftypevar
+
+@deftypevar int rl_completion_suppress_quote
+If non-zero, Readline does not append a matching quote character when
+performing completion on a quoted string.
+It is set to 0 before any application-specific completion function
+is called, and may only be changed within such a function.
+@end deftypevar
+
+@deftypevar int rl_completion_found_quote
+When Readline is completing quoted text, it sets this variable
+to a non-zero value if the word being completed contains or is delimited
+by any quoting characters, including backslashes.
+This is set before any application-specific completion function is called.
+@end deftypevar
+
+@deftypevar int rl_completion_mark_symlink_dirs
+If non-zero, a slash will be appended to completed filenames that are
+symbolic links to directory names, subject to the value of the
+user-settable @var{mark-directories} variable.
+This variable exists so that application-specific completion functions
+can override the user's global preference (set via the
+@var{mark-symlinked-directories} Readline variable) if appropriate.
+This variable is set to the user's preference before any
+application-specific completion function is called, so unless that
+function modifies the value, the user's preferences are honored.
+@end deftypevar
+
+@deftypevar int rl_ignore_completion_duplicates
+If non-zero, then duplicates in the matches are removed.
+The default is 1.
+@end deftypevar
+
+@deftypevar int rl_filename_completion_desired
+Non-zero means that the results of the matches are to be treated as
+filenames.  This is @emph{always} zero when completion is attempted,
+and can only be changed
+within an application-specific completion function.  If it is set to a
+non-zero value by such a function, directory names have a slash appended
+and Readline attempts to quote completed filenames if they contain any
+characters in @code{rl_filename_quote_characters} and
+@code{rl_filename_quoting_desired} is set to a non-zero value.
+@end deftypevar
+
+@deftypevar int rl_filename_quoting_desired
+Non-zero means that the results of the matches are to be quoted using
+double quotes (or an application-specific quoting mechanism) if the
+completed filename contains any characters in
+@code{rl_filename_quote_chars}.  This is @emph{always} non-zero
+when completion is attempted, and can only be changed within an
+application-specific completion function.
+The quoting is effected via a call to the function pointed to
+by @code{rl_filename_quoting_function}.
+@end deftypevar
+
+@deftypevar int rl_attempted_completion_over
+If an application-specific completion function assigned to
+@code{rl_attempted_completion_function} sets this variable to a non-zero
+value, Readline will not perform its default filename completion even
+if the application's completion function returns no matches.
+It should be set only by an application's completion function.
+@end deftypevar
+
+@deftypevar int rl_completion_type
+Set to a character describing the type of completion Readline is currently
+attempting; see the description of @code{rl_complete_internal()}
+(@pxref{Completion Functions}) for the list of characters.
+This is set to the appropriate value before any application-specific
+completion function is called, allowing such functions to present
+the same interface as @code{rl_complete()}.
+@end deftypevar
+
+@deftypevar int rl_inhibit_completion
+If this variable is non-zero, completion is inhibited.  The completion
+character will be inserted as any other bound to @code{self-insert}.
+@end deftypevar
+
+@node A Short Completion Example
+@subsection A Short Completion Example
+
+Here is a small application demonstrating the use of the GNU Readline
+library.  It is called @code{fileman}, and the source code resides in
+@file{examples/fileman.c}.  This sample application provides
+completion of command names, line editing features, and access to the
+history list.
+
+@page
+@smallexample
+/* fileman.c -- A tiny application which demonstrates how to use the
+   GNU Readline library.  This application interactively allows users
+   to manipulate files and their modes. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+extern char *xmalloc ();
+
+/* The names of functions that actually do the manipulation. */
+int com_list __P((char *));
+int com_view __P((char *));
+int com_rename __P((char *));
+int com_stat __P((char *));
+int com_pwd __P((char *));
+int com_delete __P((char *));
+int com_help __P((char *));
+int com_cd __P((char *));
+int com_quit __P((char *));
+
+/* A structure which contains information on the commands this program
+   can understand. */
+
+typedef struct @{
+  char *name;                  /* User printable name of the function. */
+  rl_icpfunc_t *func;          /* Function to call to do the job. */
+  char *doc;                   /* Documentation for this function.  */
+@} COMMAND;
+
+COMMAND commands[] = @{
+  @{ "cd", com_cd, "Change to directory DIR" @},
+  @{ "delete", com_delete, "Delete FILE" @},
+  @{ "help", com_help, "Display this text" @},
+  @{ "?", com_help, "Synonym for `help'" @},
+  @{ "list", com_list, "List files in DIR" @},
+  @{ "ls", com_list, "Synonym for `list'" @},
+  @{ "pwd", com_pwd, "Print the current working directory" @},
+  @{ "quit", com_quit, "Quit using Fileman" @},
+  @{ "rename", com_rename, "Rename FILE to NEWNAME" @},
+  @{ "stat", com_stat, "Print out statistics on FILE" @},
+  @{ "view", com_view, "View the contents of FILE" @},
+  @{ (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL @}
+@};
+
+/* Forward declarations. */
+char *stripwhite ();
+COMMAND *find_command ();
+
+/* The name of this program, as taken from argv[0]. */
+char *progname;
+
+/* When non-zero, this means the user is done using this program. */
+int done;
+
+char *
+dupstr (s)
+     int s;
+@{
+  char *r;
+
+  r = xmalloc (strlen (s) + 1);
+  strcpy (r, s);
+  return (r);
+@}
+
+main (argc, argv)
+     int argc;
+     char **argv;
+@{
+  char *line, *s;
+
+  progname = argv[0];
+
+  initialize_readline ();      /* Bind our completer. */
+
+  /* Loop reading and executing lines until the user quits. */
+  for ( ; done == 0; )
+    @{
+      line = readline ("FileMan: ");
+
+      if (!line)
+        break;
+
+      /* Remove leading and trailing whitespace from the line.
+         Then, if there is anything left, add it to the history list
+         and execute it. */
+      s = stripwhite (line);
+
+      if (*s)
+        @{
+          add_history (s);
+          execute_line (s);
+        @}
+
+      free (line);
+    @}
+  exit (0);
+@}
+
+/* Execute a command line. */
+int
+execute_line (line)
+     char *line;
+@{
+  register int i;
+  COMMAND *command;
+  char *word;
+
+  /* Isolate the command word. */
+  i = 0;
+  while (line[i] && whitespace (line[i]))
+    i++;
+  word = line + i;
+
+  while (line[i] && !whitespace (line[i]))
+    i++;
+
+  if (line[i])
+    line[i++] = '\0';
+
+  command = find_command (word);
+
+  if (!command)
+    @{
+      fprintf (stderr, "%s: No such command for FileMan.\n", word);
+      return (-1);
+    @}
+
+  /* Get argument to command, if any. */
+  while (whitespace (line[i]))
+    i++;
+
+  word = line + i;
+
+  /* Call the function. */
+  return ((*(command->func)) (word));
+@}
+
+/* Look up NAME as the name of a command, and return a pointer to that
+   command.  Return a NULL pointer if NAME isn't a command name. */
+COMMAND *
+find_command (name)
+     char *name;
+@{
+  register int i;
+
+  for (i = 0; commands[i].name; i++)
+    if (strcmp (name, commands[i].name) == 0)
+      return (&commands[i]);
+
+  return ((COMMAND *)NULL);
+@}
+
+/* Strip whitespace from the start and end of STRING.  Return a pointer
+   into STRING. */
+char *
+stripwhite (string)
+     char *string;
+@{
+  register char *s, *t;
+
+  for (s = string; whitespace (*s); s++)
+    ;
+    
+  if (*s == 0)
+    return (s);
+
+  t = s + strlen (s) - 1;
+  while (t > s && whitespace (*t))
+    t--;
+  *++t = '\0';
+
+  return s;
+@}
+
+/* **************************************************************** */
+/*                                                                  */
+/*                  Interface to Readline Completion                */
+/*                                                                  */
+/* **************************************************************** */
+
+char *command_generator __P((const char *, int));
+char **fileman_completion __P((const char *, int, int));
+
+/* Tell the GNU Readline library how to complete.  We want to try to
+   complete on command names if this is the first word in the line, or
+   on filenames if not. */
+initialize_readline ()
+@{
+  /* Allow conditional parsing of the ~/.inputrc file. */
+  rl_readline_name = "FileMan";
+
+  /* Tell the completer that we want a crack first. */
+  rl_attempted_completion_function = fileman_completion;
+@}
+
+/* Attempt to complete on the contents of TEXT.  START and END
+   bound the region of rl_line_buffer that contains the word to
+   complete.  TEXT is the word to complete.  We can use the entire
+   contents of rl_line_buffer in case we want to do some simple
+   parsing.  Returnthe array of matches, or NULL if there aren't any. */
+char **
+fileman_completion (text, start, end)
+     const char *text;
+     int start, end;
+@{
+  char **matches;
+
+  matches = (char **)NULL;
+
+  /* If this word is at the start of the line, then it is a command
+     to complete.  Otherwise it is the name of a file in the current
+     directory. */
+  if (start == 0)
+    matches = rl_completion_matches (text, command_generator);
+
+  return (matches);
+@}
+
+/* Generator function for command completion.  STATE lets us
+   know whether to start from scratch; without any state
+   (i.e. STATE == 0), then we start at the top of the list. */
+char *
+command_generator (text, state)
+     const char *text;
+     int state;
+@{
+  static int list_index, len;
+  char *name;
+
+  /* If this is a new word to complete, initialize now.  This
+     includes saving the length of TEXT for efficiency, and
+     initializing the index variable to 0. */
+  if (!state)
+    @{
+      list_index = 0;
+      len = strlen (text);
+    @}
+
+  /* Return the next name which partially matches from the
+     command list. */
+  while (name = commands[list_index].name)
+    @{
+      list_index++;
+
+      if (strncmp (name, text, len) == 0)
+        return (dupstr(name));
+    @}
+
+  /* If no names matched, then return NULL. */
+  return ((char *)NULL);
+@}
+
+/* **************************************************************** */
+/*                                                                  */
+/*                       FileMan Commands                           */
+/*                                                                  */
+/* **************************************************************** */
+
+/* String to pass to system ().  This is for the LIST, VIEW and RENAME
+   commands. */
+static char syscom[1024];
+
+/* List the file(s) named in arg. */
+com_list (arg)
+     char *arg;
+@{
+  if (!arg)
+    arg = "";
+
+  sprintf (syscom, "ls -FClg %s", arg);
+  return (system (syscom));
+@}
+
+com_view (arg)
+     char *arg;
+@{
+  if (!valid_argument ("view", arg))
+    return 1;
+
+  sprintf (syscom, "more %s", arg);
+  return (system (syscom));
+@}
+
+com_rename (arg)
+     char *arg;
+@{
+  too_dangerous ("rename");
+  return (1);
+@}
+
+com_stat (arg)
+     char *arg;
+@{
+  struct stat finfo;
+
+  if (!valid_argument ("stat", arg))
+    return (1);
+
+  if (stat (arg, &finfo) == -1)
+    @{
+      perror (arg);
+      return (1);
+    @}
+
+  printf ("Statistics for `%s':\n", arg);
+
+  printf ("%s has %d link%s, and is %d byte%s in length.\n", arg,
+          finfo.st_nlink,
+          (finfo.st_nlink == 1) ? "" : "s",
+          finfo.st_size,
+          (finfo.st_size == 1) ? "" : "s");
+  printf ("Inode Last Change at: %s", ctime (&finfo.st_ctime));
+  printf ("      Last access at: %s", ctime (&finfo.st_atime));
+  printf ("    Last modified at: %s", ctime (&finfo.st_mtime));
+  return (0);
+@}
+
+com_delete (arg)
+     char *arg;
+@{
+  too_dangerous ("delete");
+  return (1);
+@}
+
+/* Print out help for ARG, or for all of the commands if ARG is
+   not present. */
+com_help (arg)
+     char *arg;
+@{
+  register int i;
+  int printed = 0;
+
+  for (i = 0; commands[i].name; i++)
+    @{
+      if (!*arg || (strcmp (arg, commands[i].name) == 0))
+        @{
+          printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
+          printed++;
+        @}
+    @}
+
+  if (!printed)
+    @{
+      printf ("No commands match `%s'.  Possibilties are:\n", arg);
+
+      for (i = 0; commands[i].name; i++)
+        @{
+          /* Print in six columns. */
+          if (printed == 6)
+            @{
+              printed = 0;
+              printf ("\n");
+            @}
+
+          printf ("%s\t", commands[i].name);
+          printed++;
+        @}
+
+      if (printed)
+        printf ("\n");
+    @}
+  return (0);
+@}
+
+/* Change to the directory ARG. */
+com_cd (arg)
+     char *arg;
+@{
+  if (chdir (arg) == -1)
+    @{
+      perror (arg);
+      return 1;
+    @}
+
+  com_pwd ("");
+  return (0);
+@}
+
+/* Print out the current working directory. */
+com_pwd (ignore)
+     char *ignore;
+@{
+  char dir[1024], *s;
+
+  s = getcwd (dir, sizeof(dir) - 1);
+  if (s == 0)
+    @{
+      printf ("Error getting pwd: %s\n", dir);
+      return 1;
+    @}
+
+  printf ("Current directory is %s\n", dir);
+  return 0;
+@}
+
+/* The user wishes to quit using this program.  Just set DONE
+   non-zero. */
+com_quit (arg)
+     char *arg;
+@{
+  done = 1;
+  return (0);
+@}
+
+/* Function which tells you that you can't do this. */
+too_dangerous (caller)
+     char *caller;
+@{
+  fprintf (stderr,
+           "%s: Too dangerous for me to distribute.\n",
+           caller);
+  fprintf (stderr, "Write it yourself.\n");
+@}
+
+/* Return non-zero if ARG is a valid argument for CALLER,
+   else print an error message and return zero. */
+int
+valid_argument (caller, arg)
+     char *caller, *arg;
+@{
+  if (!arg || !*arg)
+    @{
+      fprintf (stderr, "%s: Argument required.\n", caller);
+      return (0);
+    @}
+
+  return (1);
+@}
+@end smallexample
index 8ce3bafda2a7e925b57be66669e0139d4c386179..963e0246b502418b1ec30fc0fb50a9f760b54ad0 100644 (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
index 99816bf6807e8890093a6fc6da743ca866ada705..8ce3bafda2a7e925b57be66669e0139d4c386179 100644 (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
 
index 0ec507ec27c5c9aaef808a361d521eec2d7a8031..debe3cb3fdf9b2cbc0f37b299cdec560436dbe84 100644 (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);
 }
diff --git a/lib/readline/input.c~ b/lib/readline/input.c~
new file mode 100644 (file)
index 0000000..0ec507e
--- /dev/null
@@ -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 */
index cc61388f816641fd066e813fe3462e51d350044a..eb72c19ca01916f50357c04e35c0df73249dc595 100644 (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)
diff --git a/lib/readline/terminal.c~ b/lib/readline/terminal.c~
new file mode 100644 (file)
index 0000000..d41eb62
--- /dev/null
@@ -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);
+       }
+    }
+}
index 3914c675fdcae5bfc235e58a92b1d10126ad1a61..dd0fa029aa2eeea39c16eef9fa31ec4e05e8020d 100644 (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 ()
 {
index ac5fd7446dcf611d5cea7980e63c848c15233214..fce05f1d113c793f51e8bc4407fca117db014984 100644 (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));
diff --git a/parse.y b/parse.y
index 238013fd98d3c248337abaf2c01a5dfacb459fa4..97f603b7a8c196ad597c3663f27f2684a1be1775 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -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 == '[')           /* ] */
index 3595cc0f52c49718553551e371049bf4cfe986b9..c93c6e38375988c3a9dba12c8efc0e6e11140de6 100644 (file)
@@ -1,2 +1,2 @@
 # Set of available languages.
-en@quot en@boldquot
+en@quot en@boldquot ru
diff --git a/po/ru.po b/po/ru.po
new file mode 100644 (file)
index 0000000..5eecad9
--- /dev/null
+++ b/po/ru.po
@@ -0,0 +1,2560 @@
+# Russian translations for GNU bash package
+# áÎÇÌÉÊÓËÉÅ ÐÅÒÅ×ÏÄÙ ÄÌÑ ÐÁËÅÔÁ GNU bash.
+# Copyright (C) 2006 Free Software Foundation, Inc.
+# This file is distributed under the same license as the GNU bash package.
+#  <dushistov@mail.ru>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: GNU bash 3.1-release\n"
+"POT-Creation-Date: 2005-10-03 17:31-0400\n"
+"PO-Revision-Date: 2006-01-05 21:28+0300\n"
+"Last-Translator: Evgeniy Dushistov <dushistov@mail.ru>\n"
+"Language-Team: Russian <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+
+#: arrayfunc.c:48
+msgid "bad array subscript"
+msgstr "ÎÅÐÒÁ×ÉÌØÎÙÊ ÉÎÄÅËÓ ÍÁÓÓÉ×Á"
+
+#: arrayfunc.c:360
+#, c-format
+msgid "%s: cannot assign to non-numeric index"
+msgstr "%s; ÎÅ ÍÏÇÕ ÐÒÉÐÉÓÁÔØ ÎÅ ÞÉÓÌÏ×ÏÊ ÉÎÄÅËÓ"
+
+#: bashhist.c:328
+#, c-format
+msgid "%s: cannot create: %s"
+msgstr "%s: ÎÅ ÍÏÇÕ ÓÏÚÄÁÔØ: %s"
+
+#: bashline.c:2947
+msgid "bash_execute_unix_command: cannot find keymap for command"
+msgstr ""
+
+#: bashline.c:2996
+#, c-format
+msgid "%s: first non-whitespace character is not `\"'"
+msgstr "%s: ÐÅÒ×ÙÊ ÎÅÐÒÏÂÅÌØÎÙÊ ÓÉÍ×ÏÌ ÎÅ `\"'"
+
+#: bashline.c:3025
+#, c-format
+msgid "no closing `%c' in %s"
+msgstr "ÎÅÔ ÚÁËÒÙ×ÁÀÝÅÇÏ `%c' × %s"
+
+#: bashline.c:3059
+#, c-format
+msgid "%s: missing colon separator"
+msgstr "%s: ÐÒÏÐÕÝÅΠÒÁÚÄÅÌÉÔÅÌØ Ä×ÏÅÔÏÞÉÅ"
+
+#: builtins/bind.def:194
+#, c-format
+msgid "`%s': invalid keymap name"
+msgstr ""
+
+#: builtins/bind.def:233
+#, c-format
+msgid "%s: cannot read: %s"
+msgstr "%s: ÎÅ ÍÏÇÕ ÐÒÏÞÉÔÁÔØ: %s"
+
+#: builtins/bind.def:248
+#, c-format
+msgid "`%s': cannot unbind"
+msgstr ""
+
+#: builtins/bind.def:283
+#, c-format
+msgid "`%s': unknown function name"
+msgstr "`%s': ÉÍÑ ÆÕÎËÃÉÉ ÎÅÉÚ×ÅÓÔÎÏ"
+
+#: builtins/bind.def:291
+#, c-format
+msgid "%s is not bound to any keys.\n"
+msgstr "%s ÎÅ ÐÒÉ×ÑÚÁÎÁ ÎÅ Ë ÏÄÎÏÊ ÉÚ ËÌÁ×ÉÛ.\n"
+
+#: builtins/bind.def:295
+#, c-format
+msgid "%s can be invoked via "
+msgstr "%s ÍÏÖÅÔ ÂÙÔØ ×ÙÚ×ÁΠӠÐÏÍÏÝØÀ"
+
+#: builtins/break.def:128
+msgid "only meaningful in a `for', `while', or `until' loop"
+msgstr "ÉÍÅÅÔ ÓÍÙÓÌ ÔÏÌØËÏ × ÃÉËÌÁÈ `for', `while', ÉÌÉ `until'"
+
+#: builtins/caller.def:132
+msgid "Returns the context of the current subroutine call."
+msgstr ""
+
+#: builtins/caller.def:133
+#: builtins/caller.def:137
+#: builtins/pushd.def:660
+#: builtins/pushd.def:668
+#: builtins/pushd.def:671
+#: builtins/pushd.def:681
+#: builtins/pushd.def:685
+#: builtins/pushd.def:689
+#: builtins/pushd.def:692
+#: builtins/pushd.def:695
+#: builtins/pushd.def:704
+#: builtins/pushd.def:708
+#: builtins/pushd.def:712
+#: builtins/pushd.def:715
+msgid " "
+msgstr ""
+
+#: builtins/caller.def:134
+msgid "Without EXPR, returns returns \"$line $filename\".  With EXPR,"
+msgstr "âÅÚ ÷ùòáö ×ÏÚ×ÒÁÝÁÅÔ \"$ÓÔÒÏËÁ $ÉÍÑÆÁÊÌÁ\". ó ÷ùòáö,"
+
+#: builtins/caller.def:135
+msgid "returns \"$line $subroutine $filename\"; this extra information"
+msgstr "÷ÏÚ×ÒÁÝÁÅÔ \"$ÓÔÒÏËÁ $ÐÒÏÃÅÄÕÒÁ $ÉÍÑÆÁÊÌÁ\"; ÜÔÁ ÄÏÐÏÌÎÉÔÅÌØÎÁÑ ÉÎÆÏÒÍÁÃÉÑ "
+
+#: builtins/caller.def:136
+msgid "can be used used to provide a stack trace."
+msgstr "ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎÁ ÄÌÑ ÓÏÚÄÁÎÉÑ `stack trace'"
+
+#: builtins/caller.def:138
+msgid "The value of EXPR indicates how many call frames to go back before the"
+msgstr ""
+
+#: builtins/caller.def:139
+msgid "current one; the top frame is frame 0."
+msgstr ""
+
+#: builtins/cd.def:203
+msgid "HOME not set"
+msgstr "ÐÅÒÅÍÅÎÎÁÑ HOME ÎÅ ÕÓÔÁÎÏ×ÌÅÎÁ"
+
+#: builtins/cd.def:215
+msgid "OLDPWD not set"
+msgstr "ÐÅÒÅÍÅÎÎÁÑ OLDPWD ÎÅ ÕÓÔÁÎÏ×ÌÅÎÁ"
+
+#: builtins/common.c:133
+#: test.c:921
+msgid "too many arguments"
+msgstr "ÓÌÉÛËÏÍ ÍÎÏÇÏ ÁÒÇÕÍÅÎÔÏ×"
+
+#: builtins/common.c:157
+#: shell.c:474
+#: shell.c:747
+#, c-format
+msgid "%s: option requires an argument"
+msgstr "%s: ÏÐÃÉÑ ÔÒÅÂÕÅÔ ÁÒÇÕÍÅÎÔÁ"
+
+#: builtins/common.c:164
+#, c-format
+msgid "%s: numeric argument required"
+msgstr "%s: ÔÒÅÂÕÅÔÓÑ ÞÉÓÌÏ×ÏÊ ÁÒÇÕÍÅÎÔ"
+
+#: builtins/common.c:171
+#, c-format
+msgid "%s: not found"
+msgstr "%s: ÎÅ ÎÁÊÄÅÎ"
+
+#: builtins/common.c:180
+#: shell.c:760
+#, c-format
+msgid "%s: invalid option"
+msgstr "%s: ÎÅÐÒÁ×ÉÌØÎÁÑ ÏÐÃÉÑ"
+
+#: builtins/common.c:187
+#, c-format
+msgid "%s: invalid option name"
+msgstr "%s: ÎÅÄÏÐÕÓÔÉÍÏÅ ÉÍÑ ÏÐÃÉÉ"
+
+#: builtins/common.c:194
+#: general.c:231
+#: general.c:236
+#, c-format
+msgid "`%s': not a valid identifier"
+msgstr "`%s': ÎÅÐÒÁ×ÉÌØÎÙÊ ÉÄÅÎÔÉÆÉËÁÔÏÒ"
+
+#: builtins/common.c:201
+#, c-format
+msgid "%s: invalid number"
+msgstr "%s: ÎÅÄÏÐÕÓÔÉÍÏÅ ÞÉÓÌÏ"
+
+#: builtins/common.c:208
+#, c-format
+msgid "%s: invalid signal specification"
+msgstr "%s: ÎÅÄÏÐÕÓÔÉÍÁÑ ÓÐÅÃÉÆÉËÁÃÉÑ ÓÉÇÎÁÌÁ"
+
+#: builtins/common.c:215
+#, c-format
+msgid "`%s': not a pid or valid job spec"
+msgstr "`%s': ÎÅ ÉÄÅÎÔÉÆÉËÁÔÏÒ  ÐÒÏÃÅÓÓÁ ÉÌÉ ÐÒÁ×ÉÌØÎÏÅ ÉÍÑ ÚÁÄÁÞÉ"
+
+#: builtins/common.c:222
+#: error.c:453
+#, c-format
+msgid "%s: readonly variable"
+msgstr "%s: ÄÏÓÔÕÐÎÁÑ ÔÏÌØËÏ ÎÁ ÞÔÅÎÉÅ ÐÅÒÅÍÅÎÎÁÑ"
+
+#: builtins/common.c:230
+#, c-format
+msgid "%s: %s out of range"
+msgstr "%s: %s ×ÙÈÏÄÉÔ ÚÁ ÐÒÅÄÅÌÙ ÄÏÐÕÓÔÉÍÙÈ ÚÎÁÞÅÎÉÊ"
+
+#: builtins/common.c:230
+#: builtins/common.c:232
+msgid "argument"
+msgstr "ÁÒÇÕÍÅÎÔ"
+
+#: builtins/common.c:232
+#, c-format
+msgid "%s out of range"
+msgstr "%s ×ÙÈÏÄÉÔ ÚÁ ÐÒÅÄÅÌÙ ÄÏÐÕÓÔÉÍÙÈ ÚÎÁÞÅÎÉÊ"
+
+#: builtins/common.c:240
+#, c-format
+msgid "%s: no such job"
+msgstr "%s: ÎÅ ÔÁËÏÊ ÚÁÄÁÞÉ"
+
+#: builtins/common.c:248
+#, c-format
+msgid "%s: no job control"
+msgstr ""
+
+#: builtins/common.c:250
+msgid "no job control"
+msgstr ""
+
+#: builtins/common.c:260
+#, c-format
+msgid "%s: restricted"
+msgstr ""
+
+#: builtins/common.c:262
+msgid "restricted"
+msgstr ""
+
+#: builtins/common.c:270
+#, c-format
+msgid "%s: not a shell builtin"
+msgstr "%s: ÎÅ ×ÓÔÒÏÅÎÎÁ × ÏÂÏÌÏÞËÕ"
+
+#: builtins/common.c:276
+#, c-format
+msgid "write error: %s"
+msgstr "ÏÛÉÂËÁ ÚÁÐÉÓÉ: %s"
+
+#: builtins/common.c:484
+#, c-format
+msgid "%s: error retrieving current directory: %s: %s\n"
+msgstr "%s: ÏÛÉÂËÁ ÐÏÌÕÞÅÎÉÑ ÔÅËÕÝÅÊ ÄÉÒÅËÔÏÒÉÉ: %s: %s\n"
+
+#: builtins/common.c:550
+#: builtins/common.c:552
+#, c-format
+msgid "%s: ambiguous job spec"
+msgstr ""
+
+#: builtins/complete.def:251
+#, c-format
+msgid "%s: invalid action name"
+msgstr ""
+
+#: builtins/complete.def:381
+#: builtins/complete.def:524
+#, c-format
+msgid "%s: no completion specification"
+msgstr ""
+
+#: builtins/complete.def:571
+msgid "warning: -F option may not work as you expect"
+msgstr ""
+
+#: builtins/complete.def:573
+msgid "warning: -C option may not work as you expect"
+msgstr ""
+
+#: builtins/declare.def:105
+msgid "can only be used in a function"
+msgstr "ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎÁ ÔÏÌØËÏ × ÆÕÎËÃÉÉ"
+
+#: builtins/declare.def:301
+msgid "cannot use `-f' to make functions"
+msgstr ""
+
+#: builtins/declare.def:313
+#: execute_cmd.c:3986
+#, c-format
+msgid "%s: readonly function"
+msgstr "%s: ÄÏÓÔÕÐÎÁÑ ÔÏÌØËÏ ÎÁ ÞÔÅÎÉÅ ÆÕÎËÃÉÑ"
+
+#: builtins/declare.def:401
+#, c-format
+msgid "%s: cannot destroy array variables in this way"
+msgstr "%s: ÎÅ ÍÏÇÕ ÕÄÁÌÉÔØ ÐÅÒÅÍÅÎÎÕÀ-ÍÁÓÓÉ× ÔÁËÉÍ ÓÐÏÓÏÂÏÍ"
+
+#: builtins/enable.def:128
+#: builtins/enable.def:136
+msgid "dynamic loading not available"
+msgstr ""
+
+#: builtins/enable.def:303
+#, c-format
+msgid "cannot open shared object %s: %s"
+msgstr ""
+
+#: builtins/enable.def:326
+#, c-format
+msgid "cannot find %s in shared object %s: %s"
+msgstr ""
+
+#: builtins/enable.def:450
+#, c-format
+msgid "%s: not dynamically loaded"
+msgstr ""
+
+#: builtins/enable.def:465
+#, c-format
+msgid "%s: cannot delete: %s"
+msgstr "%s: ÎÅ ÍÏÇÕ ÕÄÁÌÉÔØ:  %s"
+
+#: builtins/evalfile.c:129
+#: execute_cmd.c:3852
+#: shell.c:1408
+#, c-format
+msgid "%s: is a directory"
+msgstr "%s: Ñ×ÌÑÅÔÓÑ ÄÉÒÅËÔÏÒÉÅÊ"
+
+#: builtins/evalfile.c:134
+#, c-format
+msgid "%s: not a regular file"
+msgstr "%s: ÎÅ Ñ×ÌÑÅÔÓÑ ÏÂÙÞÎÙÍ ÆÁÊÌÏÍ"
+
+#: builtins/evalfile.c:142
+#, c-format
+msgid "%s: file is too large"
+msgstr "%s: ÓÌÉÛËÏÍ ÂÏÌØÛÏÊ ÆÁÊÌ"
+
+#: builtins/exec.def:205
+#, c-format
+msgid "%s: cannot execute: %s"
+msgstr "%s: ÎÅ ÍÏÇÕ ÚÁÐÕÓÔÉÔØ: %s"
+
+#: builtins/exit.def:83
+msgid "not login shell: use `exit'"
+msgstr "ÏÂÏÌÏÞËÁ ÎÅ Ñ×ÌÑÅÔÓÑ ÚÁÐÕÝÅÎÎÏÊ ÐÏÓÌÅ ×ÈÏÄÁ × ÓÉÓÔÅÍÕ: ÉÓÐÏÌØÚÕÊÔÅ `exit' "
+
+#: builtins/exit.def:111
+msgid "There are stopped jobs.\n"
+msgstr "åÓÔØ ÐÒÉÏÓÔÁÎÏ×ÌÅÎÎÙÅ ÚÁÄÁÞÉ.\n"
+
+#: builtins/fc.def:259
+msgid "no command found"
+msgstr "ÎÅ ÎÁÛÅÌ ÔÁËÕÀ ËÏÍÁÎÄÕ"
+
+#: builtins/fc.def:329
+msgid "history specification"
+msgstr ""
+
+#: builtins/fc.def:350
+#, c-format
+msgid "%s: cannot open temp file: %s"
+msgstr "%s: ÎÅ ÍÏÇÕ ÏÔËÒÙÔØ ×ÒÅÍÅÎÎÙÊ ÆÁÊÌ: %s"
+
+#: builtins/fg_bg.def:149
+#, c-format
+msgid "job %d started without job control"
+msgstr ""
+
+#: builtins/getopt.c:109
+#, c-format
+msgid "%s: illegal option -- %c\n"
+msgstr "%s: ÎÅÄÏÐÕÓÔÉÍÁÑ ÏÐÃÉÑ -- %c\n"
+
+#: builtins/getopt.c:110
+#, c-format
+msgid "%s: option requires an argument -- %c\n"
+msgstr ""
+
+#: builtins/hash.def:83
+msgid "hashing disabled"
+msgstr ""
+
+#: builtins/hash.def:128
+#, c-format
+msgid "%s: hash table empty\n"
+msgstr ""
+
+#: builtins/help.def:108
+msgid "Shell commands matching keywords `"
+msgstr ""
+
+#: builtins/help.def:110
+msgid "Shell commands matching keyword `"
+msgstr ""
+
+#: builtins/help.def:138
+#, c-format
+msgid "no help topics match `%s'.  Try `help help' or `man -k %s' or `info %s'."
+msgstr ""
+
+#: builtins/help.def:164
+#, c-format
+msgid "%s: cannot open: %s"
+msgstr "%s: ÎÅ ÍÏÇÕ ÏÔËÒÙÔØ: %s"
+
+#: builtins/help.def:182
+msgid ""
+"These shell commands are defined internally.  Type `help' to see this list.\n"
+"Type `help name' to find out more about the function `name'.\n"
+"Use `info bash' to find out more about the shell in general.\n"
+"Use `man -k' or `info' to find out more about commands not in this list.\n"
+"\n"
+"A star (*) next to a name means that the command is disabled.\n"
+"\n"
+msgstr ""
+
+#: builtins/history.def:150
+msgid "cannot use more than one of -anrw"
+msgstr ""
+
+#: builtins/history.def:182
+msgid "history position"
+msgstr ""
+
+#: builtins/history.def:400
+#, c-format
+msgid "%s: history expansion failed"
+msgstr ""
+
+#: builtins/jobs.def:99
+msgid "no other options allowed with `-x'"
+msgstr ""
+
+#: builtins/kill.def:187
+#, c-format
+msgid "%s: arguments must be process or job IDs"
+msgstr ""
+
+#: builtins/kill.def:250
+msgid "Unknown error"
+msgstr "îÅÉÚ×ÅÓÔÎÁÑ ÏÛÉÂËÁ"
+
+#: builtins/let.def:94
+#: builtins/let.def:119
+#: expr.c:497
+#: expr.c:512
+msgid "expression expected"
+msgstr "ÏÖÉÄÁÌÏÓØ ×ÙÒÁÖÅÎÉÅ"
+
+#: builtins/printf.def:327
+#, c-format
+msgid "`%s': missing format character"
+msgstr "`%s': ÐÒÏÐÕÝÅΠÓÉÍ×ÏÌ ÆÏÒÍÁÔÉÒÏ×ÁÎÉÑ"
+
+#: builtins/printf.def:502
+#, c-format
+msgid "`%c': invalid format character"
+msgstr "%c': ÎÅÄÏÐÕÓÔÉÍÙÊ ÓÉÍ×ÏÌ ÆÏÒÍÁÔÉÒÏ×ÁÎÉÑ"
+
+#: builtins/printf.def:708
+msgid "missing hex digit for \\x"
+msgstr ""
+
+#: builtins/pushd.def:173
+msgid "no other directory"
+msgstr "ÎÅÔ ÄÒÕÇÏÊ ÄÉÒÅËÔÏÒÉÉ"
+
+#: builtins/pushd.def:440
+msgid "<no current directory>"
+msgstr ""
+
+#: builtins/pushd.def:657
+msgid "Display the list of currently remembered directories.  Directories"
+msgstr ""
+
+#: builtins/pushd.def:658
+msgid "find their way onto the list with the `pushd' command; you can get"
+msgstr ""
+
+#: builtins/pushd.def:659
+msgid "back up through the list with the `popd' command."
+msgstr ""
+
+#: builtins/pushd.def:661
+msgid "The -l flag specifies that `dirs' should not print shorthand versions"
+msgstr ""
+
+#: builtins/pushd.def:662
+msgid "of directories which are relative to your home directory.  This means"
+msgstr ""
+
+#: builtins/pushd.def:663
+msgid "that `~/bin' might be displayed as `/homes/bfox/bin'.  The -v flag"
+msgstr ""
+
+#: builtins/pushd.def:664
+msgid "causes `dirs' to print the directory stack with one entry per line,"
+msgstr ""
+
+#: builtins/pushd.def:665
+msgid "prepending the directory name with its position in the stack.  The -p"
+msgstr ""
+
+#: builtins/pushd.def:666
+msgid "flag does the same thing, but the stack position is not prepended."
+msgstr ""
+
+#: builtins/pushd.def:667
+msgid "The -c flag clears the directory stack by deleting all of the elements."
+msgstr ""
+
+#: builtins/pushd.def:669
+msgid "+N   displays the Nth entry counting from the left of the list shown by"
+msgstr ""
+
+#: builtins/pushd.def:670
+#: builtins/pushd.def:673
+msgid "     dirs when invoked without options, starting with zero."
+msgstr ""
+
+#: builtins/pushd.def:672
+msgid "-N   displays the Nth entry counting from the right of the list shown by"
+msgstr ""
+
+#: builtins/pushd.def:678
+msgid "Adds a directory to the top of the directory stack, or rotates"
+msgstr ""
+
+#: builtins/pushd.def:679
+msgid "the stack, making the new top of the stack the current working"
+msgstr ""
+
+#: builtins/pushd.def:680
+msgid "directory.  With no arguments, exchanges the top two directories."
+msgstr ""
+
+#: builtins/pushd.def:682
+msgid "+N   Rotates the stack so that the Nth directory (counting"
+msgstr ""
+
+#: builtins/pushd.def:683
+msgid "     from the left of the list shown by `dirs', starting with"
+msgstr ""
+
+#: builtins/pushd.def:684
+#: builtins/pushd.def:688
+msgid "     zero) is at the top."
+msgstr ""
+
+#: builtins/pushd.def:686
+msgid "-N   Rotates the stack so that the Nth directory (counting"
+msgstr ""
+
+#: builtins/pushd.def:687
+msgid "     from the right of the list shown by `dirs', starting with"
+msgstr ""
+
+#: builtins/pushd.def:690
+msgid "-n   suppress the normal change of directory when adding directories"
+msgstr ""
+
+#: builtins/pushd.def:691
+msgid "     to the stack, so only the stack is manipulated."
+msgstr ""
+
+#: builtins/pushd.def:693
+msgid "dir  adds DIR to the directory stack at the top, making it the"
+msgstr ""
+
+#: builtins/pushd.def:694
+msgid "     new current working directory."
+msgstr ""
+
+#: builtins/pushd.def:696
+#: builtins/pushd.def:716
+msgid "You can see the directory stack with the `dirs' command."
+msgstr ""
+
+#: builtins/pushd.def:701
+msgid "Removes entries from the directory stack.  With no arguments,"
+msgstr ""
+
+#: builtins/pushd.def:702
+msgid "removes the top directory from the stack, and cd's to the new"
+msgstr ""
+
+#: builtins/pushd.def:703
+msgid "top directory."
+msgstr ""
+
+#: builtins/pushd.def:705
+msgid "+N   removes the Nth entry counting from the left of the list"
+msgstr ""
+
+#: builtins/pushd.def:706
+msgid "     shown by `dirs', starting with zero.  For example: `popd +0'"
+msgstr ""
+
+#: builtins/pushd.def:707
+msgid "     removes the first directory, `popd +1' the second."
+msgstr ""
+
+#: builtins/pushd.def:709
+msgid "-N   removes the Nth entry counting from the right of the list"
+msgstr ""
+
+#: builtins/pushd.def:710
+msgid "     shown by `dirs', starting with zero.  For example: `popd -0'"
+msgstr ""
+
+#: builtins/pushd.def:711
+msgid "     removes the last directory, `popd -1' the next to last."
+msgstr ""
+
+#: builtins/pushd.def:713
+msgid "-n   suppress the normal change of directory when removing directories"
+msgstr ""
+
+#: builtins/pushd.def:714
+msgid "     from the stack, so only the stack is manipulated."
+msgstr ""
+
+#: builtins/read.def:211
+#, c-format
+msgid "%s: invalid timeout specification"
+msgstr ""
+
+#: builtins/read.def:234
+#, c-format
+msgid "%s: invalid file descriptor specification"
+msgstr "%s: ÎÅÄÏÐÕÓÔÉÍÏÅ ÏÐÉÓÁÎÉÅ ÆÁÊÌÏ×ÏÇÏ ÄÅÓËÒÉÐÔÏÒÁ"
+
+#: builtins/read.def:241
+#, c-format
+msgid "%d: invalid file descriptor: %s"
+msgstr "%d: ÎÅÄÏÐÕÓÔÉÍÙÊ ÄÅÓËÒÉÐÔÏÒ ÆÁÊÌÁ: %s"
+
+#: builtins/read.def:474
+#, c-format
+msgid "read error: %d: %s"
+msgstr "ÏÛÉÂËÁ ÞÔÅÎÉÑ: %d: %s"
+
+#: builtins/return.def:63
+msgid "can only `return' from a function or sourced script"
+msgstr ""
+
+#: builtins/set.def:745
+msgid "cannot simultaneously unset a function and a variable"
+msgstr ""
+
+#: builtins/set.def:782
+#, c-format
+msgid "%s: cannot unset"
+msgstr "%s: ÎÅ ÍÏÇÕ ÓÂÒÏÓÉÔØ"
+
+#: builtins/set.def:789
+#, c-format
+msgid "%s: cannot unset: readonly %s"
+msgstr "%s: ÎÅ ÍÏÇÕ ÓÂÒÏÓÉÔØ: ÄÏÓÔÕÐÎÏ ÔÏÌØËÏ ÄÌÑ ÞÔÅÎÉÑ %s"
+
+#: builtins/set.def:800
+#, c-format
+msgid "%s: not an array variable"
+msgstr "%s: ÎÅ ÐÅÒÅÍÅÎÎÁÑ-ÍÁÓÓÉ×"
+
+#: builtins/setattr.def:166
+#, c-format
+msgid "%s: not a function"
+msgstr "%s: ÎÅ ÆÕÎËÃÉÑ"
+
+#: builtins/shift.def:66
+#: builtins/shift.def:72
+msgid "shift count"
+msgstr ""
+
+#: builtins/shopt.def:227
+msgid "cannot set and unset shell options simultaneously"
+msgstr ""
+
+#: builtins/shopt.def:292
+#, c-format
+msgid "%s: invalid shell option name"
+msgstr "%s: ÎÅÄÏÐÕÓÔÉÍÏÅ ÉÍÑ ÏÐÃÉÉ ÏÂÏÌÏÞËÉ"
+
+#: builtins/source.def:117
+msgid "filename argument required"
+msgstr "ÔÒÅÂÕÅÔÓÑ ÁÒÇÕÍÅÎÔ ÉÍÑ ÆÁÊÌÁ"
+
+#: builtins/source.def:137
+#, c-format
+msgid "%s: file not found"
+msgstr "%s: ÆÁÊÌ ÎÅ ÎÁÊÄÅÎ"
+
+#: builtins/suspend.def:93
+msgid "cannot suspend"
+msgstr ""
+
+#: builtins/suspend.def:103
+msgid "cannot suspend a login shell"
+msgstr ""
+
+#: builtins/type.def:232
+#, c-format
+msgid "%s is aliased to `%s'\n"
+msgstr ""
+
+#: builtins/type.def:253
+#, c-format
+msgid "%s is a shell keyword\n"
+msgstr "%s Ñ×ÌÑÅÔÓÑ ËÌÀÞÅ×ÙÍ ÓÌÏ×ÏÍ ÏÂÏÌÏÞËÉ\n"
+
+#: builtins/type.def:273
+#, c-format
+msgid "%s is a function\n"
+msgstr "%s Ñ×ÌÑÅÔÓÑ ÆÕÎËÃÉÅÊ\n"
+
+#: builtins/type.def:298
+#, c-format
+msgid "%s is a shell builtin\n"
+msgstr ""
+
+#: builtins/type.def:319
+#, c-format
+msgid "%s is %s\n"
+msgstr ""
+
+#: builtins/type.def:339
+#, c-format
+msgid "%s is hashed (%s)\n"
+msgstr ""
+
+#: builtins/ulimit.def:344
+#, c-format
+msgid "%s: invalid limit argument"
+msgstr ""
+
+#: builtins/ulimit.def:370
+#, c-format
+msgid "`%c': bad command"
+msgstr "`%c': ÐÌÏÈÁÑ ËÏÍÁÎÄÁ"
+
+#: builtins/ulimit.def:399
+#, c-format
+msgid "%s: cannot get limit: %s"
+msgstr ""
+
+#: builtins/ulimit.def:437
+#, c-format
+msgid "%s: cannot modify limit: %s"
+msgstr ""
+
+#: builtins/umask.def:112
+msgid "octal number"
+msgstr "ÞÉÓÌÏ × ×ÏÓØÍÅÒÉÞÎÏÊ ÓÉÓÔÅÍÅ ÉÓÞÉÓÌÅÎÉÑ"
+
+#: builtins/umask.def:226
+#, c-format
+msgid "`%c': invalid symbolic mode operator"
+msgstr ""
+
+#: builtins/umask.def:281
+#, c-format
+msgid "`%c': invalid symbolic mode character"
+msgstr ""
+
+#: error.c:165
+#, c-format
+msgid "last command: %s\n"
+msgstr "ÐÏÓÌÅÄÎÑÑ ËÏÍÁÎÄÁ: %s\n"
+
+#: error.c:173
+msgid "Aborting..."
+msgstr "úÁ×ÅÒÛÁÀ ÒÁÂÏÔÕ..."
+
+#: error.c:260
+#, c-format
+msgid "%s: warning: "
+msgstr "%s: ÐÒÅÄÕÐÒÅÖÄÅÎÉÅ:"
+
+#: error.c:405
+msgid "unknown command error"
+msgstr "ÎÅÉÚ×ÅÓÔÎÁÑ ÏÛÉÂËÁ ËÏÍÁÎÄÙ"
+
+#: error.c:406
+msgid "bad command type"
+msgstr ""
+
+#: error.c:407
+msgid "bad connector"
+msgstr ""
+
+#: error.c:408
+msgid "bad jump"
+msgstr ""
+
+#: error.c:446
+#, c-format
+msgid "%s: unbound variable"
+msgstr ""
+
+#: eval.c:176
+msgid "\atimed out waiting for input: auto-logout\n"
+msgstr ""
+
+#: execute_cmd.c:471
+#, c-format
+msgid "cannot redirect standard input from /dev/null: %s"
+msgstr ""
+
+#: execute_cmd.c:1036
+#, c-format
+msgid "TIMEFORMAT: `%c': invalid format character"
+msgstr ""
+
+#: execute_cmd.c:3551
+#, c-format
+msgid "%s: restricted: cannot specify `/' in command names"
+msgstr ""
+
+#: execute_cmd.c:3639
+#, c-format
+msgid "%s: command not found"
+msgstr "%s: ËÏÍÁÎÄÁ ÎÅ ÎÁÊÄÅÎÁ"
+
+#: execute_cmd.c:3876
+#, c-format
+msgid "%s: %s: bad interpreter"
+msgstr "%s: %s: ÐÌÏÈÏÊ ÉÎÔÅÒÐÒÅÔÁÔÏÒ"
+
+#: execute_cmd.c:3913
+#, c-format
+msgid "%s: cannot execute binary file"
+msgstr "%s: ÎÅ ÍÏÇÕ ÚÁÐÕÓÔÉÔØ ÂÉÎÁÒÎÙÊ ÆÁÊÌ"
+
+#: execute_cmd.c:4025
+#, c-format
+msgid "cannot duplicate fd %d to fd %d"
+msgstr "ÎÅ ÍÏÇÕ ÄÕÂÌÉÒÏ×ÁÔØ fd %d × fd %d"
+
+#: expr.c:240
+msgid "expression recursion level exceeded"
+msgstr ""
+
+#: expr.c:264
+msgid "recursion stack underflow"
+msgstr ""
+
+#: expr.c:375
+msgid "syntax error in expression"
+msgstr "ÓÉÎÔÁËÓÉÞÅÓËÁÑ ÏÛÉÂËÁ × ×ÙÒÁÖÅÎÉÅ"
+
+#: expr.c:415
+msgid "attempted assignment to non-variable"
+msgstr "ÐÏÐÙÔËÁ ÐÒÉÓ×ÏÅÎÉÑ ÎÅ-ÐÅÒÅÍÅÎÎÏÊ"
+
+#: expr.c:436
+#: expr.c:441
+#: expr.c:751
+msgid "division by 0"
+msgstr "ÄÅÌÅÎÉÅ ÎÁ 0"
+
+#: expr.c:467
+msgid "bug: bad expassign token"
+msgstr ""
+
+#: expr.c:509
+msgid "`:' expected for conditional expression"
+msgstr ""
+
+#: expr.c:776
+msgid "exponent less than 0"
+msgstr ""
+
+#: expr.c:821
+msgid "identifier expected after pre-increment or pre-decrement"
+msgstr ""
+
+#: expr.c:849
+msgid "missing `)'"
+msgstr "ÐÒÏÐÕÝÅΠ`)'"
+
+#: expr.c:892
+msgid "syntax error: operand expected"
+msgstr "ÏÛÉÂËÁ ÓÉÎÔÁËÓÉÓÁ: ÏÖÉÄÁÅÔÓÑ ÏÐÅÒÁÎÄ"
+
+#: expr.c:1178
+msgid "invalid number"
+msgstr "ÎÅÄÏÐÕÓÔÉÍÏÅ ÞÉÓÌÏ"
+
+#: expr.c:1182
+msgid "invalid arithmetic base"
+msgstr ""
+
+#: expr.c:1202
+msgid "value too great for base"
+msgstr ""
+
+#: general.c:62
+msgid "getcwd: cannot access parent directories"
+msgstr ""
+
+#: input.c:231
+#, c-format
+msgid "cannot allocate new file descriptor for bash input from fd %d"
+msgstr ""
+
+#: input.c:239
+#, c-format
+msgid "save_bash_input: buffer already exists for new fd %d"
+msgstr ""
+
+#: jobs.c:923
+#, c-format
+msgid "deleting stopped job %d with process group %ld"
+msgstr ""
+
+#: jobs.c:1308
+#, c-format
+msgid "describe_pid: %ld: no such pid"
+msgstr ""
+
+#: jobs.c:1981
+#: nojobs.c:648
+#, c-format
+msgid "wait: pid %ld is not a child of this shell"
+msgstr ""
+
+#: jobs.c:2180
+#, c-format
+msgid "wait_for: No record of process %ld"
+msgstr ""
+
+#: jobs.c:2435
+#, c-format
+msgid "wait_for_job: job %d is stopped"
+msgstr ""
+
+#: jobs.c:2657
+#, c-format
+msgid "%s: job has terminated"
+msgstr ""
+
+#: jobs.c:2666
+#, c-format
+msgid "%s: job %d already in background"
+msgstr ""
+
+#: jobs.c:3452
+msgid "no job control in this shell"
+msgstr ""
+
+#: lib/malloc/malloc.c:298
+#, c-format
+msgid "malloc: failed assertion: %s\n"
+msgstr ""
+
+#: lib/malloc/malloc.c:314
+#, c-format
+msgid ""
+"\r\n"
+"malloc: %s:%d: assertion botched\r\n"
+msgstr ""
+
+#: lib/malloc/malloc.c:740
+msgid "malloc: block on free list clobbered"
+msgstr ""
+
+#: lib/malloc/malloc.c:817
+msgid "free: called with already freed block argument"
+msgstr ""
+
+#: lib/malloc/malloc.c:820
+msgid "free: called with unallocated block argument"
+msgstr ""
+
+#: lib/malloc/malloc.c:839
+msgid "free: underflow detected; mh_nbytes out of range"
+msgstr ""
+
+#: lib/malloc/malloc.c:845
+msgid "free: start and end chunk sizes differ"
+msgstr ""
+
+#: lib/malloc/malloc.c:942
+msgid "realloc: called with unallocated block argument"
+msgstr ""
+
+#: lib/malloc/malloc.c:957
+msgid "realloc: underflow detected; mh_nbytes out of range"
+msgstr ""
+
+#: lib/malloc/malloc.c:963
+msgid "realloc: start and end chunk sizes differ"
+msgstr ""
+
+#: lib/malloc/table.c:175
+msgid "register_alloc: alloc table is full with FIND_ALLOC?\n"
+msgstr ""
+
+#: lib/malloc/table.c:182
+#, c-format
+msgid "register_alloc: %p already in table as allocated?\n"
+msgstr ""
+
+#: lib/malloc/table.c:218
+#, c-format
+msgid "register_free: %p already in table as free?\n"
+msgstr ""
+
+#: lib/malloc/watch.c:46
+msgid "allocated"
+msgstr ""
+
+#: lib/malloc/watch.c:48
+msgid "freed"
+msgstr ""
+
+#: lib/malloc/watch.c:50
+msgid "requesting resize"
+msgstr ""
+
+#: lib/malloc/watch.c:52
+msgid "just resized"
+msgstr ""
+
+#: lib/malloc/watch.c:54
+msgid "bug: unknown operation"
+msgstr "ÏÛÉÂËÁ: ÎÅÉÚ×ÅÓÔÎÁÑ ÏÐÅÒÁÃÉÑ"
+
+#: lib/malloc/watch.c:56
+#, c-format
+msgid "malloc: watch alert: %p %s "
+msgstr ""
+
+#: lib/sh/fmtulong.c:101
+msgid "invalid base"
+msgstr ""
+
+#: lib/sh/netopen.c:158
+#, c-format
+msgid "%s: host unknown"
+msgstr "%s: ÈÏÓÔ ÎÅÉÚ×ÅÓÔÅÎ"
+
+#: lib/sh/netopen.c:165
+#, c-format
+msgid "%s: invalid service"
+msgstr "%s: ÎÅÄÏÐÕÓÔÉÍÙÊ ÓÅÒ×ÉÓ"
+
+#: lib/sh/netopen.c:296
+#, c-format
+msgid "%s: bad network path specification"
+msgstr ""
+
+#: lib/sh/netopen.c:336
+msgid "network operations not supported"
+msgstr ""
+
+#: mailcheck.c:386
+msgid "You have mail in $_"
+msgstr "õ ×ÁÓ ÅÓÔØ ÐÏÞÔÁ × $_"
+
+#: mailcheck.c:411
+msgid "You have new mail in $_"
+msgstr "õ ×ÁÓ ÅÓÔØ ÎÏ×ÁÑ ÐÏÞÔÁ × $_"
+
+#: mailcheck.c:427
+#, c-format
+msgid "The mail in %s has been read\n"
+msgstr "ðÏÞÔÁ × %s ÂÙÌÁ ÐÒÏÞÉÔÁÎÁ\n"
+
+#: make_cmd.c:322
+msgid "syntax error: arithmetic expression required"
+msgstr ""
+
+#: make_cmd.c:324
+msgid "syntax error: `;' unexpected"
+msgstr "ÏÛÉÂËÁ ÓÉÎÔÁËÓÉÓÁ: `;' ÎÅ ÏÖÉÄÁÅÔÓÑ"
+
+#: make_cmd.c:325
+#, c-format
+msgid "syntax error: `((%s))'"
+msgstr "ÏÛÉÂËÁ ÓÉÎÔÁËÓÉÓÁ: `((%s))'"
+
+#: make_cmd.c:566
+#, c-format
+msgid "make_here_document: bad instruction type %d"
+msgstr ""
+
+#: make_cmd.c:736
+#, c-format
+msgid "make_redirection: redirection instruction `%d' out of range"
+msgstr ""
+
+#: parse.y:2747
+#, c-format
+msgid "unexpected EOF while looking for matching `%c'"
+msgstr ""
+
+#: parse.y:3043
+msgid "unexpected EOF while looking for `]]'"
+msgstr ""
+
+#: parse.y:3048
+#, c-format
+msgid "syntax error in conditional expression: unexpected token `%s'"
+msgstr ""
+
+#: parse.y:3052
+msgid "syntax error in conditional expression"
+msgstr ""
+
+#: parse.y:3130
+#, c-format
+msgid "unexpected token `%s', expected `)'"
+msgstr ""
+
+#: parse.y:3134
+msgid "expected `)'"
+msgstr "ÏÖÉÄÁÌÓÑ `)'"
+
+#: parse.y:3162
+#, c-format
+msgid "unexpected argument `%s' to conditional unary operator"
+msgstr ""
+
+#: parse.y:3166
+msgid "unexpected argument to conditional unary operator"
+msgstr ""
+
+#: parse.y:3203
+#, c-format
+msgid "unexpected token `%s', conditional binary operator expected"
+msgstr ""
+
+#: parse.y:3207
+msgid "conditional binary operator expected"
+msgstr ""
+
+#: parse.y:3223
+#, c-format
+msgid "unexpected argument `%s' to conditional binary operator"
+msgstr ""
+
+#: parse.y:3227
+msgid "unexpected argument to conditional binary operator"
+msgstr ""
+
+#: parse.y:3238
+#, c-format
+msgid "unexpected token `%c' in conditional command"
+msgstr ""
+
+#: parse.y:3241
+#, c-format
+msgid "unexpected token `%s' in conditional command"
+msgstr ""
+
+#: parse.y:3245
+#, c-format
+msgid "unexpected token %d in conditional command"
+msgstr ""
+
+#: parse.y:4461
+#, c-format
+msgid "syntax error near unexpected token `%s'"
+msgstr ""
+
+#: parse.y:4479
+#, c-format
+msgid "syntax error near `%s'"
+msgstr "ÏÛÉÂËÁ ÓÉÎÔÁËÓÉÓÁ ÏËÏÌÏ `%s'"
+
+#: parse.y:4489
+msgid "syntax error: unexpected end of file"
+msgstr "ÏÛÉÂËÁ ÓÉÎÔÁËÓÉÓÁ: ÎÅÏÖÉÄÁÎÎÙÊ ËÏÎÅàÆÁÊÌÁ"
+
+#: parse.y:4489
+msgid "syntax error"
+msgstr "ÏÛÉÂËÁ ÓÉÎÔÁËÓÉÓÁ"
+
+#: parse.y:4551
+#, c-format
+msgid "Use \"%s\" to leave the shell.\n"
+msgstr "éÓÐÏÌØÚÕÊÔÅ \"%s\", ÞÔÏÂÙ ÚÁ×ÅÒÛÉÔØÓÑ ÒÁÂÏÔÕ Ó  ÏÂÏÌÏÞËÏÊ.\n"
+
+#: parse.y:4710
+msgid "unexpected EOF while looking for matching `)'"
+msgstr ""
+
+#: pcomplete.c:1001
+#, c-format
+msgid "completion: function `%s' not found"
+msgstr ""
+
+#: pcomplib.c:179
+#, c-format
+msgid "progcomp_insert: %s: NULL COMPSPEC"
+msgstr ""
+
+#: print_cmd.c:264
+#, c-format
+msgid "print_command: bad connector `%d'"
+msgstr ""
+
+#: print_cmd.c:1236
+#, c-format
+msgid "cprintf: `%c': invalid format character"
+msgstr ""
+
+#: redir.c:99
+msgid "file descriptor out of range"
+msgstr "ÆÁÊÌÏ×ÙÊ ÄÅÓËÒÉÐÔÏÒ ÚÁ ÐÒÅÄÅÌÁÍÉ ÄÏÐÕÓÔÉÍÏÇÏ ÄÉÁÐÁÚÏÎÁ"
+
+#: redir.c:141
+#, c-format
+msgid "%s: ambiguous redirect"
+msgstr ""
+
+#: redir.c:145
+#, c-format
+msgid "%s: cannot overwrite existing file"
+msgstr "%s: ÎÅ ÍÏÇÕ ÐÅÒÅÐÉÓÁÔØ ÕÖÅ ÓÕÝÅÓÔ×ÕÀÝÉÊ ÆÁÊÌ"
+
+#: redir.c:150
+#, c-format
+msgid "%s: restricted: cannot redirect output"
+msgstr ""
+
+#: redir.c:155
+#, c-format
+msgid "cannot create temp file for here document: %s"
+msgstr ""
+
+#: redir.c:509
+msgid "/dev/(tcp|udp)/host/port not supported without networking"
+msgstr ""
+
+#: redir.c:956
+msgid "redirection error: cannot duplicate fd"
+msgstr "ÏÛÉÂËÁ ÐÅÒÅÎÁÐÒÁ×ÌÅÎÉÑ: ÎÅ ÍÏÇÕ ÄÕÂÌÉÒÏ×ÁÔØ fd"
+
+#: shell.c:309
+msgid "could not find /tmp, please create!"
+msgstr "ÎÅ ÍÏÇÕ ÎÁÊÔÉ /tmp, ÐÏÖÁÌÕÊÓÔÁ ÓÏÚÄÁÊÔÅ!"
+
+#: shell.c:313
+msgid "/tmp must be a valid directory name"
+msgstr "/tmp ÄÏÌÖÎÁ ÂÙÔØ ÄÅÊÓÔ×ÉÔÅÌØÎÙÍ ÉÍÅÎÅÍ ÄÉÒÅËÔÏÒÉÉ"
+
+#: shell.c:849
+#, c-format
+msgid "%c%c: invalid option"
+msgstr "%c%c: ÎÅÄÏÐÕÓÔÉÍÁÑ ÏÐÃÉÑ"
+
+#: shell.c:1598
+msgid "I have no name!"
+msgstr "õ ÍÅÎÑ ÎÅÔ ÉÍÅÎÉ!"
+
+#: shell.c:1733
+#, c-format
+msgid ""
+"Usage:\t%s [GNU long option] [option] ...\n"
+"\t%s [GNU long option] [option] script-file ...\n"
+msgstr ""
+"éÓÐÏÌØÚÏ×ÁÎÉÅ:\n"
+"%s [ÄÌÉÎÎÙÅ ÏÐÃÉÉ Á-ÌÑ `GNU'] [ÏÐÃÉÉ] ...\n"
+"\t%s [ÄÌÉÎÎÙÅ ÏÐÃÉÉ Á-ÌÑ `GNU'] [ÏÐÃÉÉ] ÆÁÊÌ_ÓÏ_ÓËÒÉÐÔÏÍ...\n"
+
+#: shell.c:1735
+msgid "GNU long options:\n"
+msgstr "äÌÉÎÎÙÅ ÏÐÃÉÉ × ÓÔÅÌÅ GNU:\n"
+
+#: shell.c:1739
+msgid "Shell options:\n"
+msgstr "ïÐÃÉÉ ÏÂÏÌÏÞËÉ:\n"
+
+#: shell.c:1740
+msgid "\t-irsD or -c command or -O shopt_option\t\t(invocation only)\n"
+msgstr ""
+
+#: shell.c:1755
+#, c-format
+msgid "\t-%s or -o option\n"
+msgstr "\t-%s ÉÌÉ ÏÐÃÉÑ -o\n"
+
+#: shell.c:1761
+#, c-format
+msgid "Type `%s -c \"help set\"' for more information about shell options.\n"
+msgstr ""
+
+#: shell.c:1762
+#, c-format
+msgid "Type `%s -c help' for more information about shell builtin commands.\n"
+msgstr ""
+
+#: shell.c:1763
+msgid "Use the `bashbug' command to report bugs.\n"
+msgstr ""
+
+#: sig.c:494
+#, c-format
+msgid "sigprocmask: %d: invalid operation"
+msgstr ""
+
+#: subst.c:1123
+#, c-format
+msgid "bad substitution: no closing `%s' in %s"
+msgstr ""
+
+#: subst.c:2269
+#, c-format
+msgid "%s: cannot assign list to array member"
+msgstr ""
+
+#: subst.c:4208
+#: subst.c:4224
+msgid "cannot make pipe for process substitution"
+msgstr ""
+
+#: subst.c:4255
+msgid "cannot make child for process substitution"
+msgstr ""
+
+#: subst.c:4300
+#, c-format
+msgid "cannot open named pipe %s for reading"
+msgstr "ÎÅ ÍÏÇÕ ÏÔËÒÙÔØ ÉÍÅÎÎÏÊ ËÁÎÁÌ %s ÄÌÑ ÞÔÅÎÉÑ"
+
+#: subst.c:4302
+#, c-format
+msgid "cannot open named pipe %s for writing"
+msgstr "ÎÅ ÍÏÇÕ ÏÔËÒÙÔØ ÉÍÅÎÎÏÊ ËÁÎÁÌ %s ÄÌÑ ÚÁÐÉÓÉ"
+
+#: subst.c:4310
+#, c-format
+msgid "cannout reset nodelay mode for fd %d"
+msgstr ""
+
+#: subst.c:4320
+#, c-format
+msgid "cannot duplicate named pipe %s as fd %d"
+msgstr ""
+
+#: subst.c:4495
+msgid "cannot make pipe for command substitution"
+msgstr ""
+
+#: subst.c:4531
+msgid "cannot make child for command substitution"
+msgstr ""
+
+#: subst.c:4548
+msgid "command_substitute: cannot duplicate pipe as fd 1"
+msgstr ""
+
+#: subst.c:5013
+#, c-format
+msgid "%s: parameter null or not set"
+msgstr "%s: ÐÁÒÁÍÅÔÒ null ÉÌÉ ÎÅ ÕÓÔÁÎÏ×ÌÅÎ"
+
+#: subst.c:5287
+#, c-format
+msgid "%s: substring expression < 0"
+msgstr ""
+
+#: subst.c:6058
+#, c-format
+msgid "%s: bad substitution"
+msgstr ""
+
+#: subst.c:6134
+#, c-format
+msgid "$%s: cannot assign in this way"
+msgstr ""
+
+#: subst.c:7687
+#, c-format
+msgid "no match: %s"
+msgstr "ÎÅÔ ÓÏ×ÐÁÄÅÎÉÑ Ó: %s"
+
+#: test.c:154
+msgid "argument expected"
+msgstr "ÐÒÅÄÐÏÌÁÇÁÅÔÓÑ ÞÔÏ ÂÕÄÅÔ ÉÓÐÏÌØÚÏ×ÁΠÁÒÇÕÍÅÎÔ"
+
+#: test.c:163
+#, c-format
+msgid "%s: integer expression expected"
+msgstr ""
+
+#: test.c:361
+msgid "`)' expected"
+msgstr "ÏÖÉÄÁÅÔÓÑ `)' "
+
+#: test.c:363
+#, c-format
+msgid "`)' expected, found %s"
+msgstr "ÏÖÉÄÁÌÓÑ `)', ÎÁÊÄÅΠ%s"
+
+#: test.c:378
+#: test.c:787
+#: test.c:790
+#, c-format
+msgid "%s: unary operator expected"
+msgstr "%s: ÏÖÉÄÁÅÔÓÑ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÕÎÁÒÎÏÇÏ ÏÐÅÒÁÔÏÒÁ"
+
+#: test.c:543
+#: test.c:830
+#, c-format
+msgid "%s: binary operator expected"
+msgstr "%s: ÏÖÉÄÁÅÔÓÑ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÂÉÎÁÒÎÏÇÏ ÏÐÅÒÁÔÏÒÁ"
+
+#: test.c:905
+msgid "missing `]'"
+msgstr "ÐÒÏÐÕÝÅΠ`]'"
+
+#: trap.c:194
+msgid "invalid signal number"
+msgstr "ÎÅÄÏÐÕÓÔÉÍÙÊ ÎÏÍÅÒ ÓÉÇÎÁÌÁ"
+
+#: trap.c:309
+#, c-format
+msgid "run_pending_traps: bad value in trap_list[%d]: %p"
+msgstr ""
+
+#: trap.c:313
+#, c-format
+msgid "run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"
+msgstr ""
+
+#: trap.c:349
+#, c-format
+msgid "trap_handler: bad signal %d"
+msgstr ""
+
+#: variables.c:320
+#, c-format
+msgid "error importing function definition for `%s'"
+msgstr ""
+
+#: variables.c:692
+#, c-format
+msgid "shell level (%d) too high, resetting to 1"
+msgstr ""
+
+#: variables.c:1651
+msgid "make_local_variable: no function context at current scope"
+msgstr ""
+
+#: variables.c:2807
+msgid "all_local_variables: no function context at current scope"
+msgstr ""
+
+#: variables.c:3021
+#: variables.c:3030
+#, c-format
+msgid "invalid character %d in exportstr for %s"
+msgstr ""
+
+#: variables.c:3036
+#, c-format
+msgid "no `=' in exportstr for %s"
+msgstr ""
+
+#: variables.c:3463
+msgid "pop_var_context: head of shell_variables not a function context"
+msgstr ""
+
+#: variables.c:3476
+msgid "pop_var_context: no global_variables context"
+msgstr ""
+
+#: variables.c:3548
+msgid "pop_scope: head of shell_variables not a temporary environment scope"
+msgstr ""
+
+#: version.c:82
+msgid "Copyright (C) 2005 Free Software Foundation, Inc.\n"
+msgstr ""
+
+#: xmalloc.c:93
+#, c-format
+msgid "xmalloc: cannot allocate %lu bytes (%lu bytes allocated)"
+msgstr ""
+
+#: xmalloc.c:95
+#, c-format
+msgid "xmalloc: cannot allocate %lu bytes"
+msgstr ""
+
+#: xmalloc.c:115
+#, c-format
+msgid "xrealloc: cannot reallocate %lu bytes (%lu bytes allocated)"
+msgstr ""
+
+#: xmalloc.c:117
+#, c-format
+msgid "xrealloc: cannot allocate %lu bytes"
+msgstr ""
+
+#: xmalloc.c:151
+#, c-format
+msgid "xmalloc: %s:%d: cannot allocate %lu bytes (%lu bytes allocated)"
+msgstr ""
+
+#: xmalloc.c:153
+#, c-format
+msgid "xmalloc: %s:%d: cannot allocate %lu bytes"
+msgstr ""
+
+#: xmalloc.c:175
+#, c-format
+msgid "xrealloc: %s:%d: cannot reallocate %lu bytes (%lu bytes allocated)"
+msgstr ""
+
+#: xmalloc.c:177
+#, c-format
+msgid "xrealloc: %s:%d: cannot allocate %lu bytes"
+msgstr ""
+
+#: builtins.c:244
+msgid ""
+" `alias' with no arguments or with the -p option prints the list\n"
+"    of aliases in the form alias NAME=VALUE on standard output.\n"
+"    Otherwise, an alias is defined for each NAME whose VALUE is given.\n"
+"    A trailing space in VALUE causes the next word to be checked for\n"
+"    alias substitution when the alias is expanded.  Alias returns\n"
+"    true unless a NAME is given for which no alias has been defined."
+msgstr ""
+
+#: builtins.c:257
+msgid ""
+" Remove NAMEs from the list of defined aliases.  If the -a option is given,\n"
+"    then remove all alias definitions."
+msgstr ""
+
+#: builtins.c:266
+msgid ""
+" Bind a key sequence to a Readline function or a macro, or set\n"
+"    a Readline variable.  The non-option argument syntax is equivalent\n"
+"    to that found in ~/.inputrc, but must be passed as a single argument:\n"
+"    bind '\"\\C-x\\C-r\": re-read-init-file'.\n"
+"    bind accepts the following options:\n"
+"      -m  keymap         Use `keymap' as the keymap for the duration of this\n"
+"                         command.  Acceptable keymap names are emacs,\n"
+"                         emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move,\n"
+"                         vi-command, and vi-insert.\n"
+"      -l                 List names of functions.\n"
+"      -P                 List function names and bindings.\n"
+"      -p                 List functions and bindings in a form that can be\n"
+"                         reused as input.\n"
+"      -r  keyseq         Remove the binding for KEYSEQ.\n"
+"      -x  keyseq:shell-command\tCause SHELL-COMMAND to be executed when\n"
+"    \t\t\t\tKEYSEQ is entered.\n"
+"      -f  filename       Read key bindings from FILENAME.\n"
+"      -q  function-name  Query about which keys invoke the named function.\n"
+"      -u  function-name  Unbind all keys which are bound to the named function.\n"
+"      -V                 List variable names and values\n"
+"      -v                 List variable names and values in a form that can\n"
+"                         be reused as input.\n"
+"      -S                 List key sequences that invoke macros and their values\n"
+"      -s                 List key sequences that invoke macros and their values\n"
+"                         in a form that can be reused as input."
+msgstr ""
+
+#: builtins.c:297
+msgid ""
+" Exit from within a FOR, WHILE or UNTIL loop.  If N is specified,\n"
+"    break N levels."
+msgstr ""
+
+#: builtins.c:304
+msgid ""
+" Resume the next iteration of the enclosing FOR, WHILE or UNTIL loop.\n"
+"    If N is specified, resume at the N-th enclosing loop."
+msgstr ""
+
+#: builtins.c:311
+msgid ""
+" Run a shell builtin.  This is useful when you wish to rename a\n"
+"    shell builtin to be a function, but need the functionality of the\n"
+"    builtin within the function itself."
+msgstr ""
+
+#: builtins.c:320
+msgid ""
+" Returns the context of the current subroutine call.\n"
+"    \n"
+"    Without EXPR, returns returns \"$line $filename\".  With EXPR,\n"
+"    returns \"$line $subroutine $filename\"; this extra information\n"
+"    can be used used to provide a stack trace.\n"
+"    \n"
+"    The value of EXPR indicates how many call frames to go back before the\n"
+"    current one; the top frame is frame 0."
+msgstr ""
+
+#: builtins.c:334
+msgid ""
+" Change the current directory to DIR.  The variable $HOME is the\n"
+"    default DIR.  The variable CDPATH defines the search path for\n"
+"    the directory containing DIR.  Alternative directory names in CDPATH\n"
+"    are separated by a colon (:).  A null directory name is the same as\n"
+"    the current directory, i.e. `.'.  If DIR begins with a slash (/),\n"
+"    then CDPATH is not used.  If the directory is not found, and the\n"
+"    shell option `cdable_vars' is set, then try the word as a variable\n"
+"    name.  If that variable has a value, then cd to the value of that\n"
+"    variable.  The -P option says to use the physical directory structure\n"
+"    instead of following symbolic links; the -L option forces symbolic links\n"
+"    to be followed."
+msgstr ""
+
+#: builtins.c:350
+msgid ""
+" Print the current working directory.  With the -P option, pwd prints\n"
+"    the physical directory, without any symbolic links; the -L option\n"
+"    makes pwd follow symbolic links."
+msgstr ""
+
+#: builtins.c:358
+msgid " No effect; the command does nothing.  A zero exit code is returned."
+msgstr " îÅÔ ËÁËÏÇÏ-ÌÉÂÏ ÜÆÆÅËÔÁ; ËÏÍÁÎÄÁ ÎÉÞÅÇÏ ÎÅ ÄÅÌÁÅÔ. îÕÌØ ×ÏÚ×ÒÁÝÁÅÔÓÑ × ËÁÞÅÓÔ×Å ÒÅÚÕÌØÔÁÔÁ."
+
+#: builtins.c:364
+msgid " Return a successful result."
+msgstr "÷ÏÚ×ÒÁÝÁÅÔ ÒÅÚÕÌØÔÁÔ: ×ÓÅ ÈÏÒÏÛÏ."
+
+#: builtins.c:370
+msgid " Return an unsuccessful result."
+msgstr "÷ÏÚ×ÒÁÝÁÅÔ ÒÅÚÕÌØÔÁÔ: ÎÅÕÄÁÞÁ."
+
+#: builtins.c:376
+msgid ""
+" Runs COMMAND with ARGS ignoring shell functions.  If you have a shell\n"
+"    function called `ls', and you wish to call the command `ls', you can\n"
+"    say \"command ls\".  If the -p option is given, a default value is used\n"
+"    for PATH that is guaranteed to find all of the standard utilities.  If\n"
+"    the -V or -v option is given, a string is printed describing COMMAND.\n"
+"    The -V option produces a more verbose description."
+msgstr ""
+
+#: builtins.c:387
+msgid ""
+" Declare variables and/or give them attributes.  If no NAMEs are\n"
+"    given, then display the values of variables instead.  The -p option\n"
+"    will display the attributes and values of each NAME.\n"
+"    \n"
+"    The flags are:\n"
+"    \n"
+"      -a\tto make NAMEs arrays (if supported)\n"
+"      -f\tto select from among function names only\n"
+"      -F\tto display function names (and line number and source file name if\n"
+"    \tdebugging) without definitions\n"
+"      -i\tto make NAMEs have the `integer' attribute\n"
+"      -r\tto make NAMEs readonly\n"
+"      -t\tto make NAMEs have the `trace' attribute\n"
+"      -x\tto make NAMEs export\n"
+"    \n"
+"    Variables with the integer attribute have arithmetic evaluation (see\n"
+"    `let') done when the variable is assigned to.\n"
+"    \n"
+"    When displaying values of variables, -f displays a function's name\n"
+"    and definition.  The -F option restricts the display to function\n"
+"    name only.\n"
+"    \n"
+"    Using `+' instead of `-' turns off the given attribute instead.  When\n"
+"    used in a function, makes NAMEs local, as with the `local' command."
+msgstr ""
+
+#: builtins.c:416
+msgid " Obsolete.  See `declare'."
+msgstr " ÷ÙÛÅÌ ÉÚ ÕÐÏÔÒÅÂÌÅÎÉÑ. óÍ. `declare'."
+
+#: builtins.c:422
+msgid ""
+" Create a local variable called NAME, and give it VALUE.  LOCAL\n"
+"    can only be used within a function; it makes the variable NAME\n"
+"    have a visible scope restricted to that function and its children."
+msgstr ""
+
+#: builtins.c:431
+msgid ""
+" Output the ARGs.  If -n is specified, the trailing newline is\n"
+"    suppressed.  If the -e option is given, interpretation of the\n"
+"    following backslash-escaped characters is turned on:\n"
+"    \t\\a\talert (bell)\n"
+"    \t\\b\tbackspace\n"
+"    \t\\c\tsuppress trailing newline\n"
+"    \t\\E\tescape character\n"
+"    \t\\f\tform feed\n"
+"    \t\\n"
+"\tnew line\n"
+"    \t\\r\tcarriage return\n"
+"    \t\\t\thorizontal tab\n"
+"    \t\\v\tvertical tab\n"
+"    \t\\\\\tbackslash\n"
+"    \t\\n"
+"um\tthe character whose ASCII code is NUM (octal).\n"
+"    \n"
+"    You can explicitly turn off the interpretation of the above characters\n"
+"    with the -E option."
+msgstr ""
+
+#: builtins.c:455
+msgid " Output the ARGs.  If -n is specified, the trailing newline is suppressed."
+msgstr ""
+
+#: builtins.c:462
+msgid ""
+" Enable and disable builtin shell commands.  This allows\n"
+"    you to use a disk command which has the same name as a shell\n"
+"    builtin without specifying a full pathname.  If -n is used, the\n"
+"    NAMEs become disabled; otherwise NAMEs are enabled.  For example,\n"
+"    to use the `test' found in $PATH instead of the shell builtin\n"
+"    version, type `enable -n test'.  On systems supporting dynamic\n"
+"    loading, the -f option may be used to load new builtins from the\n"
+"    shared object FILENAME.  The -d option will delete a builtin\n"
+"    previously loaded with -f.  If no non-option names are given, or\n"
+"    the -p option is supplied, a list of builtins is printed.  The\n"
+"    -a option means to print every builtin with an indication of whether\n"
+"    or not it is enabled.  The -s option restricts the output to the POSIX.2\n"
+"    `special' builtins.  The -n option displays a list of all disabled builtins."
+msgstr ""
+
+#: builtins.c:480
+msgid " Read ARGs as input to the shell and execute the resulting command(s)."
+msgstr ""
+
+#: builtins.c:486
+msgid ""
+" Getopts is used by shell procedures to parse positional parameters.\n"
+"    \n"
+"    OPTSTRING contains the option letters to be recognized; if a letter\n"
+"    is followed by a colon, the option is expected to have an argument,\n"
+"    which should be separated from it by white space.\n"
+"    \n"
+"    Each time it is invoked, getopts will place the next option in the\n"
+"    shell variable $name, initializing name if it does not exist, and\n"
+"    the index of the next argument to be processed into the shell\n"
+"    variable OPTIND.  OPTIND is initialized to 1 each time the shell or\n"
+"    a shell script is invoked.  When an option requires an argument,\n"
+"    getopts places that argument into the shell variable OPTARG.\n"
+"    \n"
+"    getopts reports errors in one of two ways.  If the first character\n"
+"    of OPTSTRING is a colon, getopts uses silent error reporting.  In\n"
+"    this mode, no error messages are printed.  If an invalid option is\n"
+"    seen, getopts places the option character found into OPTARG.  If a\n"
+"    required argument is not found, getopts places a ':' into NAME and\n"
+"    sets OPTARG to the option character found.  If getopts is not in\n"
+"    silent mode, and an invalid option is seen, getopts places '?' into\n"
+"    NAME and unsets OPTARG.  If a required argument is not found, a '?'\n"
+"    is placed in NAME, OPTARG is unset, and a diagnostic message is\n"
+"    printed.\n"
+"    \n"
+"    If the shell variable OPTERR has the value 0, getopts disables the\n"
+"    printing of error messages, even if the first character of\n"
+"    OPTSTRING is not a colon.  OPTERR has the value 1 by default.\n"
+"    \n"
+"    Getopts normally parses the positional parameters ($0 - $9), but if\n"
+"    more arguments are given, they are parsed instead."
+msgstr ""
+
+#: builtins.c:521
+msgid ""
+" Exec FILE, replacing this shell with the specified program.\n"
+"    If FILE is not specified, the redirections take effect in this\n"
+"    shell.  If the first argument is `-l', then place a dash in the\n"
+"    zeroth arg passed to FILE, as login does.  If the `-c' option\n"
+"    is supplied, FILE is executed with a null environment.  The `-a'\n"
+"    option means to make set argv[0] of the executed process to NAME.\n"
+"    If the file cannot be executed and the shell is not interactive,\n"
+"    then the shell exits, unless the shell option `execfail' is set."
+msgstr ""
+
+#: builtins.c:534
+msgid ""
+" Exit the shell with a status of N.  If N is omitted, the exit status\n"
+"    is that of the last command executed."
+msgstr ""
+
+#: builtins.c:541
+msgid " Logout of a login shell."
+msgstr "úÁ×ÅÒÛÅÎÉÑ ÓÅÁÎÓÁ ËÏÍÁÎÄÎÏÇÏ ÉÎÔÅÒÐÒÅÔÁÔÏÒÁ ÚÁÐÕÝÅÎÎÏÇÏ ÐÏÓÌÅ ×ÈÏÄÁ × ÓÉÓÔÅÍÕ."
+
+#: builtins.c:548
+msgid ""
+" fc is used to list or edit and re-execute commands from the history list.\n"
+"    FIRST and LAST can be numbers specifying the range, or FIRST can be a\n"
+"    string, which means the most recent command beginning with that\n"
+"    string.\n"
+"    \n"
+"       -e ENAME selects which editor to use.  Default is FCEDIT, then EDITOR,\n"
+"          then vi.\n"
+"    \n"
+"       -l means list lines instead of editing.\n"
+"       -n means no line numbers listed.\n"
+"       -r means reverse the order of the lines (making it newest listed first).\n"
+"    \n"
+"    With the `fc -s [pat=rep ...] [command]' format, the command is\n"
+"    re-executed after the substitution OLD=NEW is performed.\n"
+"    \n"
+"    A useful alias to use with this is r='fc -s', so that typing `r cc'\n"
+"    runs the last command beginning with `cc' and typing `r' re-executes\n"
+"    the last command."
+msgstr ""
+
+#: builtins.c:573
+msgid ""
+" Place JOB_SPEC in the foreground, and make it the current job.  If\n"
+"    JOB_SPEC is not present, the shell's notion of the current job is\n"
+"    used."
+msgstr ""
+
+#: builtins.c:583
+msgid ""
+" Place each JOB_SPEC in the background, as if it had been started with\n"
+"    `&'.  If JOB_SPEC is not present, the shell's notion of the current\n"
+"    job is used."
+msgstr ""
+
+#: builtins.c:592
+msgid ""
+" For each NAME, the full pathname of the command is determined and\n"
+"    remembered.  If the -p option is supplied, PATHNAME is used as the\n"
+"    full pathname of NAME, and no path search is performed.  The -r\n"
+"    option causes the shell to forget all remembered locations.  The -d\n"
+"    option causes the shell to forget the remembered location of each NAME.\n"
+"    If the -t option is supplied the full pathname to which each NAME\n"
+"    corresponds is printed.  If multiple NAME arguments are supplied with\n"
+"    -t, the NAME is printed before the hashed full pathname.  The -l option\n"
+"    causes output to be displayed in a format that may be reused as input.\n"
+"    If no arguments are given, information about remembered commands is displayed."
+msgstr ""
+
+#: builtins.c:608
+msgid ""
+" Display helpful information about builtin commands.  If PATTERN is\n"
+"    specified, gives detailed help on all commands matching PATTERN,\n"
+"    otherwise a list of the builtins is printed.  The -s option\n"
+"    restricts the output for each builtin command matching PATTERN to\n"
+"    a short usage synopsis."
+msgstr ""
+
+#: builtins.c:620
+msgid ""
+" Display the history list with line numbers.  Lines listed with\n"
+"    with a `*' have been modified.  Argument of N says to list only\n"
+"    the last N lines.  The `-c' option causes the history list to be\n"
+"    cleared by deleting all of the entries.  The `-d' option deletes\n"
+"    the history entry at offset OFFSET.  The `-w' option writes out the\n"
+"    current history to the history file;  `-r' means to read the file and\n"
+"    append the contents to the history list instead.  `-a' means\n"
+"    to append history lines from this session to the history file.\n"
+"    Argument `-n' means to read all history lines not already read\n"
+"    from the history file and append them to the history list.\n"
+"    \n"
+"    If FILENAME is given, then that is used as the history file else\n"
+"    if $HISTFILE has a value, that is used, else ~/.bash_history.\n"
+"    If the -s option is supplied, the non-option ARGs are appended to\n"
+"    the history list as a single entry.  The -p option means to perform\n"
+"    history expansion on each ARG and display the result, without storing\n"
+"    anything in the history list.\n"
+"    \n"
+"    If the $HISTTIMEFORMAT variable is set and not null, its value is used\n"
+"    as a format string for strftime(3) to print the time stamp associated\n"
+"    with each displayed history entry.  No time stamps are printed otherwise."
+msgstr ""
+
+#: builtins.c:648
+msgid ""
+" Lists the active jobs.  The -l option lists process id's in addition\n"
+"    to the normal information; the -p option lists process id's only.\n"
+"    If -n is given, only processes that have changed status since the last\n"
+"    notification are printed.  JOBSPEC restricts output to that job.  The\n"
+"    -r and -s options restrict output to running and stopped jobs only,\n"
+"    respectively.  Without options, the status of all active jobs is\n"
+"    printed.  If -x is given, COMMAND is run after all job specifications\n"
+"    that appear in ARGS have been replaced with the process ID of that job's\n"
+"    process group leader."
+msgstr ""
+
+#: builtins.c:664
+msgid ""
+" By default, removes each JOBSPEC argument from the table of active jobs.\n"
+"    If the -h option is given, the job is not removed from the table, but is\n"
+"    marked so that SIGHUP is not sent to the job if the shell receives a\n"
+"    SIGHUP.  The -a option, when JOBSPEC is not supplied, means to remove all\n"
+"    jobs from the job table; the -r option means to remove only running jobs."
+msgstr ""
+
+#: builtins.c:675
+msgid ""
+" Send the processes named by PID (or JOBSPEC) the signal SIGSPEC.  If\n"
+"    SIGSPEC is not present, then SIGTERM is assumed.  An argument of `-l'\n"
+"    lists the signal names; if arguments follow `-l' they are assumed to\n"
+"    be signal numbers for which names should be listed.  Kill is a shell\n"
+"    builtin for two reasons: it allows job IDs to be used instead of\n"
+"    process IDs, and, if you have reached the limit on processes that\n"
+"    you can create, you don't have to start a process to kill another one."
+msgstr ""
+
+#: builtins.c:687
+msgid ""
+" Each ARG is an arithmetic expression to be evaluated.  Evaluation\n"
+"    is done in fixed-width integers with no check for overflow, though\n"
+"    division by 0 is trapped and flagged as an error.  The following\n"
+"    list of operators is grouped into levels of equal-precedence operators.\n"
+"    The levels are listed in order of decreasing precedence.\n"
+"    \n"
+"    \tid++, id--\tvariable post-increment, post-decrement\n"
+"    \t++id, --id\tvariable pre-increment, pre-decrement\n"
+"    \t-, +\t\tunary minus, plus\n"
+"    \t!, ~\t\tlogical and bitwise negation\n"
+"    \t**\t\texponentiation\n"
+"    \t*, /, %\t\tmultiplication, division, remainder\n"
+"    \t+, -\t\taddition, subtraction\n"
+"    \t<<, >>\t\tleft and right bitwise shifts\n"
+"    \t<=, >=, <, >\tcomparison\n"
+"    \t==, !=\t\tequality, inequality\n"
+"    \t&\t\tbitwise AND\n"
+"    \t^\t\tbitwise XOR\n"
+"    \t|\t\tbitwise OR\n"
+"    \t&&\t\tlogical AND\n"
+"    \t||\t\tlogical OR\n"
+"    \texpr ? expr : expr\n"
+"    \t\t\tconditional operator\n"
+"    \t=, *=, /=, %=,\n"
+"    \t+=, -=, <<=, >>=,\n"
+"    \t&=, ^=, |=\tassignment\n"
+"    \n"
+"    Shell variables are allowed as operands.  The name of the variable\n"
+"    is replaced by its value (coerced to a fixed-width integer) within\n"
+"    an expression.  The variable need not have its integer attribute\n"
+"    turned on to be used in an expression.\n"
+"    \n"
+"    Operators are evaluated in order of precedence.  Sub-expressions in\n"
+"    parentheses are evaluated first and may override the precedence\n"
+"    rules above.\n"
+"    \n"
+"    If the last ARG evaluates to 0, let returns 1; 0 is returned\n"
+"    otherwise."
+msgstr ""
+
+#: builtins.c:730
+msgid ""
+" One line is read from the standard input, or from file descriptor FD if the\n"
+"    -u option is supplied, and the first word is assigned to the first NAME,\n"
+"    the second word to the second NAME, and so on, with leftover words assigned\n"
+"    to the last NAME.  Only the characters found in $IFS are recognized as word\n"
+"    delimiters.  If no NAMEs are supplied, the line read is stored in the REPLY\n"
+"    variable.  If the -r option is given, this signifies `raw' input, and\n"
+"    backslash escaping is disabled.  The -d option causes read to continue\n"
+"    until the first character of DELIM is read, rather than newline.  If the -p\n"
+"    option is supplied, the string PROMPT is output without a trailing newline\n"
+"    before attempting to read.  If -a is supplied, the words read are assigned\n"
+"    to sequential indices of ARRAY, starting at zero.  If -e is supplied and\n"
+"    the shell is interactive, readline is used to obtain the line.  If -n is\n"
+"    supplied with a non-zero NCHARS argument, read returns after NCHARS\n"
+"    characters have been read.  The -s option causes input coming from a\n"
+"    terminal to not be echoed.\n"
+"    \n"
+"    The -t option causes read to time out and return failure if a complete line\n"
+"    of input is not read within TIMEOUT seconds.  If the TMOUT variable is set,\n"
+"    its value is the default timeout.  The return code is zero, unless end-of-file\n"
+"    is encountered, read times out, or an invalid file descriptor is supplied as\n"
+"    the argument to -u."
+msgstr ""
+
+#: builtins.c:756
+msgid ""
+" Causes a function to exit with the return value specified by N.  If N\n"
+"    is omitted, the return status is that of the last command."
+msgstr ""
+
+#: builtins.c:763
+msgid ""
+"     -a  Mark variables which are modified or created for export.\n"
+"        -b  Notify of job termination immediately.\n"
+"        -e  Exit immediately if a command exits with a non-zero status.\n"
+"        -f  Disable file name generation (globbing).\n"
+"        -h  Remember the location of commands as they are looked up.\n"
+"        -k  All assignment arguments are placed in the environment for a\n"
+"            command, not just those that precede the command name.\n"
+"        -m  Job control is enabled.\n"
+"        -n  Read commands but do not execute them.\n"
+"        -o option-name\n"
+"            Set the variable corresponding to option-name:\n"
+"                allexport    same as -a\n"
+"                braceexpand  same as -B\n"
+"                emacs        use an emacs-style line editing interface\n"
+"                errexit      same as -e\n"
+"                errtrace     same as -E\n"
+"                functrace    same as -T\n"
+"                hashall      same as -h\n"
+"                histexpand   same as -H\n"
+"                history      enable command history\n"
+"                ignoreeof    the shell will not exit upon reading EOF\n"
+"                interactive-comments\n"
+"                             allow comments to appear in interactive commands\n"
+"                keyword      same as -k\n"
+"                monitor      same as -m\n"
+"                noclobber    same as -C\n"
+"                noexec       same as -n\n"
+"                noglob       same as -f\n"
+"                nolog        currently accepted but ignored\n"
+"                notify       same as -b\n"
+"                nounset      same as -u\n"
+"                onecmd       same as -t\n"
+"                physical     same as -P\n"
+"                pipefail     the return value of a pipeline is the status of\n"
+"                             the last command to exit with a non-zero status,\n"
+"                             or zero if no command exited with a non-zero status\n"
+"                posix        change the behavior of bash where the default\n"
+"                             operation differs from the 1003.2 standard to\n"
+"                             match the standard\n"
+"                privileged   same as -p\n"
+"                verbose      same as -v\n"
+"                vi           use a vi-style line editing interface\n"
+"                xtrace       same as -x\n"
+"        -p  Turned on whenever the real and effective user ids do not match.\n"
+"            Disables processing of the $ENV file and importing of shell\n"
+"            functions.  Turning this option off causes the effective uid and\n"
+"            gid to be set to the real uid and gid.\n"
+"        -t  Exit after reading and executing one command.\n"
+"        -u  Treat unset variables as an error when substituting.\n"
+"        -v  Print shell input lines as they are read.\n"
+"        -x  Print commands and their arguments as they are executed.\n"
+"        -B  the shell will perform brace expansion\n"
+"        -C  If set, disallow existing regular files to be overwritten\n"
+"            by redirection of output.\n"
+"        -E  If set, the ERR trap is inherited by shell functions.\n"
+"        -H  Enable ! style history substitution.  This flag is on\n"
+"            by default when the shell is interactive.\n"
+"        -P  If set, do not follow symbolic links when executing commands\n"
+"            such as cd which change the current directory.\n"
+"        -T  If set, the DEBUG trap is inherited by shell functions.\n"
+"        -   Assign any remaining arguments to the positional parameters.\n"
+"            The -x and -v options are turned off.\n"
+"    \n"
+"    Using + rather than - causes these flags to be turned off.  The\n"
+"    flags can also be used upon invocation of the shell.  The current\n"
+"    set of flags may be found in $-.  The remaining n ARGs are positional\n"
+"    parameters and are assigned, in order, to $1, $2, .. $n.  If no\n"
+"    ARGs are given, all shell variables are printed."
+msgstr ""
+
+#: builtins.c:836
+msgid ""
+" For each NAME, remove the corresponding variable or function.  Given\n"
+"    the `-v', unset will only act on variables.  Given the `-f' flag,\n"
+"    unset will only act on functions.  With neither flag, unset first\n"
+"    tries to unset a variable, and if that fails, then tries to unset a\n"
+"    function.  Some variables cannot be unset; also see readonly."
+msgstr ""
+
+#: builtins.c:846
+msgid ""
+" NAMEs are marked for automatic export to the environment of\n"
+"    subsequently executed commands.  If the -f option is given,\n"
+"    the NAMEs refer to functions.  If no NAMEs are given, or if `-p'\n"
+"    is given, a list of all names that are exported in this shell is\n"
+"    printed.  An argument of `-n' says to remove the export property\n"
+"    from subsequent NAMEs.  An argument of `--' disables further option\n"
+"    processing."
+msgstr ""
+
+#: builtins.c:858
+msgid ""
+" The given NAMEs are marked readonly and the values of these NAMEs may\n"
+"    not be changed by subsequent assignment.  If the -f option is given,\n"
+"    then functions corresponding to the NAMEs are so marked.  If no\n"
+"    arguments are given, or if `-p' is given, a list of all readonly names\n"
+"    is printed.  The `-a' option means to treat each NAME as\n"
+"    an array variable.  An argument of `--' disables further option\n"
+"    processing."
+msgstr ""
+
+#: builtins.c:870
+msgid ""
+" The positional parameters from $N+1 ... are renamed to $1 ...  If N is\n"
+"    not given, it is assumed to be 1."
+msgstr ""
+
+#: builtins.c:877
+#: builtins.c:886
+msgid ""
+" Read and execute commands from FILENAME and return.  The pathnames\n"
+"    in $PATH are used to find the directory containing FILENAME.  If any\n"
+"    ARGUMENTS are supplied, they become the positional parameters when\n"
+"    FILENAME is executed."
+msgstr ""
+
+#: builtins.c:896
+msgid ""
+" Suspend the execution of this shell until it receives a SIGCONT\n"
+"    signal.  The `-f' if specified says not to complain about this\n"
+"    being a login shell if it is; just suspend anyway."
+msgstr ""
+
+#: builtins.c:905
+msgid ""
+" Exits with a status of 0 (true) or 1 (false) depending on\n"
+"    the evaluation of EXPR.  Expressions may be unary or binary.  Unary\n"
+"    expressions are often used to examine the status of a file.  There\n"
+"    are string operators as well, and numeric comparison operators.\n"
+"    \n"
+"    File operators:\n"
+"    \n"
+"        -a FILE        True if file exists.\n"
+"        -b FILE        True if file is block special.\n"
+"        -c FILE        True if file is character special.\n"
+"        -d FILE        True if file is a directory.\n"
+"        -e FILE        True if file exists.\n"
+"        -f FILE        True if file exists and is a regular file.\n"
+"        -g FILE        True if file is set-group-id.\n"
+"        -h FILE        True if file is a symbolic link.\n"
+"        -L FILE        True if file is a symbolic link.\n"
+"        -k FILE        True if file has its `sticky' bit set.\n"
+"        -p FILE        True if file is a named pipe.\n"
+"        -r FILE        True if file is readable by you.\n"
+"        -s FILE        True if file exists and is not empty.\n"
+"        -S FILE        True if file is a socket.\n"
+"        -t FD          True if FD is opened on a terminal.\n"
+"        -u FILE        True if the file is set-user-id.\n"
+"        -w FILE        True if the file is writable by you.\n"
+"        -x FILE        True if the file is executable by you.\n"
+"        -O FILE        True if the file is effectively owned by you.\n"
+"        -G FILE        True if the file is effectively owned by your group.\n"
+"        -N FILE        True if the file has been modified since it was last read.\n"
+"    \n"
+"      FILE1 -nt FILE2  True if file1 is newer than file2 (according to\n"
+"                       modification date).\n"
+"    \n"
+"      FILE1 -ot FILE2  True if file1 is older than file2.\n"
+"    \n"
+"      FILE1 -ef FILE2  True if file1 is a hard link to file2.\n"
+"    \n"
+"    String operators:\n"
+"    \n"
+"        -z STRING      True if string is empty.\n"
+"    \n"
+"        -n STRING\n"
+"        STRING         True if string is not empty.\n"
+"    \n"
+"        STRING1 = STRING2\n"
+"                       True if the strings are equal.\n"
+"        STRING1 != STRING2\n"
+"                       True if the strings are not equal.\n"
+"        STRING1 < STRING2\n"
+"                       True if STRING1 sorts before STRING2 lexicographically.\n"
+"        STRING1 > STRING2\n"
+"                       True if STRING1 sorts after STRING2 lexicographically.\n"
+"    \n"
+"    Other operators:\n"
+"    \n"
+"        -o OPTION      True if the shell option OPTION is enabled.\n"
+"        ! EXPR         True if expr is false.\n"
+"        EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.\n"
+"        EXPR1 -o EXPR2 True if either expr1 OR expr2 is true.\n"
+"    \n"
+"        arg1 OP arg2   Arithmetic tests.  OP is one of -eq, -ne,\n"
+"                       -lt, -le, -gt, or -ge.\n"
+"    \n"
+"    Arithmetic binary operators return true if ARG1 is equal, not-equal,\n"
+"    less-than, less-than-or-equal, greater-than, or greater-than-or-equal\n"
+"    than ARG2."
+msgstr ""
+
+#: builtins.c:975
+msgid ""
+" This is a synonym for the \"test\" builtin, but the last\n"
+"    argument must be a literal `]', to match the opening `['."
+msgstr ""
+
+#: builtins.c:982
+msgid ""
+" Print the accumulated user and system times for processes run from\n"
+"    the shell."
+msgstr ""
+
+#: builtins.c:989
+msgid ""
+" The command ARG is to be read and executed when the shell receives\n"
+"    signal(s) SIGNAL_SPEC.  If ARG is absent (and a single SIGNAL_SPEC\n"
+"    is supplied) or `-', each specified signal is reset to its original\n"
+"    value.  If ARG is the null string each SIGNAL_SPEC is ignored by the\n"
+"    shell and by the commands it invokes.  If a SIGNAL_SPEC is EXIT (0)\n"
+"    the command ARG is executed on exit from the shell.  If a SIGNAL_SPEC\n"
+"    is DEBUG, ARG is executed after every simple command.  If the`-p' option\n"
+"    is supplied then the trap commands associated with each SIGNAL_SPEC are\n"
+"    displayed.  If no arguments are supplied or if only `-p' is given, trap\n"
+"    prints the list of commands associated with each signal.  Each SIGNAL_SPEC\n"
+"    is either a signal name in <signal.h> or a signal number.  Signal names\n"
+"    are case insensitive and the SIG prefix is optional.  `trap -l' prints\n"
+"    a list of signal names and their corresponding numbers.  Note that a\n"
+"    signal can be sent to the shell with \"kill -signal $$\"."
+msgstr ""
+
+#: builtins.c:1008
+msgid ""
+" For each NAME, indicate how it would be interpreted if used as a\n"
+"    command name.\n"
+"    \n"
+"    If the -t option is used, `type' outputs a single word which is one of\n"
+"    `alias', `keyword', `function', `builtin', `file' or `', if NAME is an\n"
+"    alias, shell reserved word, shell function, shell builtin, disk file,\n"
+"    or unfound, respectively.\n"
+"    \n"
+"    If the -p flag is used, `type' either returns the name of the disk\n"
+"    file that would be executed, or nothing if `type -t NAME' would not\n"
+"    return `file'.\n"
+"    \n"
+"    If the -a flag is used, `type' displays all of the places that contain\n"
+"    an executable named `file'.  This includes aliases, builtins, and\n"
+"    functions, if and only if the -p flag is not also used.\n"
+"    \n"
+"    The -f flag suppresses shell function lookup.\n"
+"    \n"
+"    The -P flag forces a PATH search for each NAME, even if it is an alias,\n"
+"    builtin, or function, and returns the name of the disk file that would\n"
+"    be executed."
+msgstr ""
+
+#: builtins.c:1035
+msgid ""
+" Ulimit provides control over the resources available to processes\n"
+"    started by the shell, on systems that allow such control.  If an\n"
+"    option is given, it is interpreted as follows:\n"
+"    \n"
+"        -S\tuse the `soft' resource limit\n"
+"        -H\tuse the `hard' resource limit\n"
+"        -a\tall current limits are reported\n"
+"        -c\tthe maximum size of core files created\n"
+"        -d\tthe maximum size of a process's data segment\n"
+"        -f\tthe maximum size of files created by the shell\n"
+"        -i  the maximum number of pending signals\n"
+"        -l\tthe maximum size a process may lock into memory\n"
+"        -m\tthe maximum resident set size\n"
+"        -n\tthe maximum number of open file descriptors\n"
+"        -p\tthe pipe buffer size\n"
+"        -q  the maximum number of bytes in POSIX message queues\n"
+"        -s\tthe maximum stack size\n"
+"        -t\tthe maximum amount of cpu time in seconds\n"
+"        -u\tthe maximum number of user processes\n"
+"        -v\tthe size of virtual memory\n"
+"        -x  the maximum number of file locks\n"
+"    \n"
+"    If LIMIT is given, it is the new value of the specified resource;\n"
+"    the special LIMIT values `soft', `hard', and `unlimited' stand for\n"
+"    the current soft limit, the current hard limit, and no limit, respectively.\n"
+"    Otherwise, the current value of the specified resource is printed.\n"
+"    If no option is given, then -f is assumed.  Values are in 1024-byte\n"
+"    increments, except for -t, which is in seconds, -p, which is in\n"
+"    increments of 512 bytes, and -u, which is an unscaled number of\n"
+"    processes."
+msgstr ""
+
+#: builtins.c:1071
+msgid ""
+" The user file-creation mask is set to MODE.  If MODE is omitted, or if\n"
+"    `-S' is supplied, the current value of the mask is printed.  The `-S'\n"
+"    option makes the output symbolic; otherwise an octal number is output.\n"
+"    If `-p' is supplied, and MODE is omitted, the output is in a form\n"
+"    that may be used as input.  If MODE begins with a digit, it is\n"
+"    interpreted as an octal number, otherwise it is a symbolic mode string\n"
+"    like that accepted by chmod(1)."
+msgstr ""
+
+#: builtins.c:1084
+msgid ""
+" Wait for the specified process and report its termination status.  If\n"
+"    N is not given, all currently active child processes are waited for,\n"
+"    and the return code is zero.  N may be a process ID or a job\n"
+"    specification; if a job spec is given, all processes in the job's\n"
+"    pipeline are waited for."
+msgstr ""
+
+#: builtins.c:1096
+msgid ""
+" Wait for the specified process and report its termination status.  If\n"
+"    N is not given, all currently active child processes are waited for,\n"
+"    and the return code is zero.  N is a process ID; if it is not given,\n"
+"    all child processes of the shell are waited for."
+msgstr ""
+
+#: builtins.c:1106
+msgid ""
+" The `for' loop executes a sequence of commands for each member in a\n"
+"    list of items.  If `in WORDS ...;' is not present, then `in \"$@\"' is\n"
+"    assumed.  For each element in WORDS, NAME is set to that element, and\n"
+"    the COMMANDS are executed."
+msgstr ""
+
+#: builtins.c:1115
+msgid ""
+" Equivalent to\n"
+"    \t(( EXP1 ))\n"
+"    \twhile (( EXP2 )); do\n"
+"    \t\tCOMMANDS\n"
+"    \t\t(( EXP3 ))\n"
+"    \tdone\n"
+"    EXP1, EXP2, and EXP3 are arithmetic expressions.  If any expression is\n"
+"    omitted, it behaves as if it evaluates to 1."
+msgstr ""
+
+#: builtins.c:1128
+msgid ""
+" The WORDS are expanded, generating a list of words.  The\n"
+"    set of expanded words is printed on the standard error, each\n"
+"    preceded by a number.  If `in WORDS' is not present, `in \"$@\"'\n"
+"    is assumed.  The PS3 prompt is then displayed and a line read\n"
+"    from the standard input.  If the line consists of the number\n"
+"    corresponding to one of the displayed words, then NAME is set\n"
+"    to that word.  If the line is empty, WORDS and the prompt are\n"
+"    redisplayed.  If EOF is read, the command completes.  Any other\n"
+"    value read causes NAME to be set to null.  The line read is saved\n"
+"    in the variable REPLY.  COMMANDS are executed after each selection\n"
+"    until a break command is executed."
+msgstr ""
+
+#: builtins.c:1144
+msgid ""
+" Execute PIPELINE and print a summary of the real time, user CPU time,\n"
+"    and system CPU time spent executing PIPELINE when it terminates.\n"
+"    The return status is the return status of PIPELINE.  The `-p' option\n"
+"    prints the timing summary in a slightly different format.  This uses\n"
+"    the value of the TIMEFORMAT variable as the output format."
+msgstr ""
+
+#: builtins.c:1154
+msgid ""
+" Selectively execute COMMANDS based upon WORD matching PATTERN.  The\n"
+"    `|' is used to separate multiple patterns."
+msgstr ""
+
+#: builtins.c:1161
+msgid ""
+" The `if COMMANDS' list is executed.  If its exit status is zero, then the\n"
+"    `then COMMANDS' list is executed.  Otherwise, each `elif COMMANDS' list is\n"
+"    executed in turn, and if its exit status is zero, the corresponding\n"
+"    `then COMMANDS' list is executed and the if command completes.  Otherwise,\n"
+"    the `else COMMANDS' list is executed, if present.  The exit status of the\n"
+"    entire construct is the exit status of the last command executed, or zero\n"
+"    if no condition tested true."
+msgstr ""
+
+#: builtins.c:1173
+msgid ""
+" Expand and execute COMMANDS as long as the final command in the\n"
+"    `while' COMMANDS has an exit status of zero."
+msgstr ""
+
+#: builtins.c:1180
+msgid ""
+" Expand and execute COMMANDS as long as the final command in the\n"
+"    `until' COMMANDS has an exit status which is not zero."
+msgstr ""
+
+#: builtins.c:1187
+msgid ""
+" Create a simple command invoked by NAME which runs COMMANDS.\n"
+"    Arguments on the command line along with NAME are passed to the\n"
+"    function as $0 .. $n."
+msgstr ""
+
+#: builtins.c:1195
+msgid ""
+" Run a set of commands in a group.  This is one way to redirect an\n"
+"    entire set of commands."
+msgstr ""
+
+#: builtins.c:1202
+msgid ""
+" Equivalent to the JOB_SPEC argument to the `fg' command.  Resume a\n"
+"    stopped or background job.  JOB_SPEC can specify either a job name\n"
+"    or a job number.  Following JOB_SPEC with a `&' places the job in\n"
+"    the background, as if the job specification had been supplied as an\n"
+"    argument to `bg'."
+msgstr ""
+
+#: builtins.c:1212
+msgid ""
+" The EXPRESSION is evaluated according to the rules for arithmetic\n"
+"    evaluation.  Equivalent to \"let EXPRESSION\"."
+msgstr ""
+
+#: builtins.c:1219
+msgid ""
+" Returns a status of 0 or 1 depending on the evaluation of the conditional\n"
+"    expression EXPRESSION.  Expressions are composed of the same primaries used\n"
+"    by the `test' builtin, and may be combined using the following operators\n"
+"    \n"
+"    \t( EXPRESSION )\tReturns the value of EXPRESSION\n"
+"    \t! EXPRESSION\tTrue if EXPRESSION is false; else false\n"
+"    \tEXPR1 && EXPR2\tTrue if both EXPR1 and EXPR2 are true; else false\n"
+"    \tEXPR1 || EXPR2\tTrue if either EXPR1 or EXPR2 is true; else false\n"
+"    \n"
+"    When the `==' and `!=' operators are used, the string to the right of the\n"
+"    operator is used as a pattern and pattern matching is performed.  The\n"
+"    && and || operators do not evaluate EXPR2 if EXPR1 is sufficient to\n"
+"    determine the expression's value."
+msgstr ""
+
+#: builtins.c:1237
+msgid ""
+" BASH_VERSION    Version information for this Bash.\n"
+"    CDPATH          A colon-separated list of directories to search\n"
+"    \t\tfor directries given as arguments to `cd'.\n"
+"    GLOBIGNORE\tA colon-separated list of patterns describing filenames to\n"
+"    \t\tbe ignored by pathname expansion.\n"
+"    HISTFILE        The name of the file where your command history is stored.\n"
+"    HISTFILESIZE    The maximum number of lines this file can contain.\n"
+"    HISTSIZE        The maximum number of history lines that a running\n"
+"    \t\tshell can access.\n"
+"    HOME            The complete pathname to your login directory.\n"
+"    HOSTNAME\tThe name of the current host.\n"
+"    HOSTTYPE        The type of CPU this version of Bash is running under.\n"
+"    IGNOREEOF       Controls the action of the shell on receipt of an EOF\n"
+"    \t\tcharacter as the sole input.  If set, then the value\n"
+"    \t\tof it is the number of EOF characters that can be seen\n"
+"    \t\tin a row on an empty line before the shell will exit\n"
+"    \t\t(default 10).  When unset, EOF signifies the end of input.\n"
+"    MACHTYPE\tA string describing the current system Bash is running on.\n"
+"    MAILCHECK\tHow often, in seconds, Bash checks for new mail.\n"
+"    MAILPATH\tA colon-separated list of filenames which Bash checks\n"
+"    \t\tfor new mail.\n"
+"    OSTYPE\t\tThe version of Unix this version of Bash is running on.\n"
+"    PATH            A colon-separated list of directories to search when\n"
+"    \t\tlooking for commands.\n"
+"    PROMPT_COMMAND  A command to be executed before the printing of each\n"
+"    \t\tprimary prompt.\n"
+"    PS1             The primary prompt string.\n"
+"    PS2             The secondary prompt string.\n"
+"    PWD\t\tThe full pathname of the current directory.\n"
+"    SHELLOPTS\tA colon-separated list of enabled shell options.\n"
+"    TERM            The name of the current terminal type.\n"
+"    TIMEFORMAT\tThe output format for timing statistics displayed by the\n"
+"    \t\t`time' reserved word.\n"
+"    auto_resume     Non-null means a command word appearing on a line by\n"
+"    \t\titself is first looked for in the list of currently\n"
+"    \t\tstopped jobs.  If found there, that job is foregrounded.\n"
+"    \t\tA value of `exact' means that the command word must\n"
+"    \t\texactly match a command in the list of stopped jobs.  A\n"
+"    \t\tvalue of `substring' means that the command word must\n"
+"    \t\tmatch a substring of the job.  Any other value means that\n"
+"    \t\tthe command must be a prefix of a stopped job.\n"
+"    histchars       Characters controlling history expansion and quick\n"
+"    \t\tsubstitution.  The first character is the history\n"
+"    \t\tsubstitution character, usually `!'.  The second is\n"
+"    \t\tthe `quick substitution' character, usually `^'.  The\n"
+"    \t\tthird is the `history comment' character, usually `#'.\n"
+"    HISTIGNORE\tA colon-separated list of patterns used to decide which\n"
+"    \t\tcommands should be saved on the history list.\n"
+msgstr ""
+
+#: builtins.c:1292
+msgid ""
+" Adds a directory to the top of the directory stack, or rotates\n"
+"    the stack, making the new top of the stack the current working\n"
+"    directory.  With no arguments, exchanges the top two directories.\n"
+"    \n"
+"    +N\tRotates the stack so that the Nth directory (counting\n"
+"    \tfrom the left of the list shown by `dirs', starting with\n"
+"    \tzero) is at the top.\n"
+"    \n"
+"    -N\tRotates the stack so that the Nth directory (counting\n"
+"    \tfrom the right of the list shown by `dirs', starting with\n"
+"    \tzero) is at the top.\n"
+"    \n"
+"    -n\tsuppress the normal change of directory when adding directories\n"
+"    \tto the stack, so only the stack is manipulated.\n"
+"    \n"
+"    dir\tadds DIR to the directory stack at the top, making it the\n"
+"    \tnew current working directory.\n"
+"    \n"
+"    You can see the directory stack with the `dirs' command."
+msgstr ""
+
+#: builtins.c:1318
+msgid ""
+" Removes entries from the directory stack.  With no arguments,\n"
+"    removes the top directory from the stack, and cd's to the new\n"
+"    top directory.\n"
+"    \n"
+"    +N\tremoves the Nth entry counting from the left of the list\n"
+"    \tshown by `dirs', starting with zero.  For example: `popd +0'\n"
+"    \tremoves the first directory, `popd +1' the second.\n"
+"    \n"
+"    -N\tremoves the Nth entry counting from the right of the list\n"
+"    \tshown by `dirs', starting with zero.  For example: `popd -0'\n"
+"    \tremoves the last directory, `popd -1' the next to last.\n"
+"    \n"
+"    -n\tsuppress the normal change of directory when removing directories\n"
+"    \tfrom the stack, so only the stack is manipulated.\n"
+"    \n"
+"    You can see the directory stack with the `dirs' command."
+msgstr ""
+
+#: builtins.c:1341
+msgid ""
+" Display the list of currently remembered directories.  Directories\n"
+"    find their way onto the list with the `pushd' command; you can get\n"
+"    back up through the list with the `popd' command.\n"
+"    \n"
+"    The -l flag specifies that `dirs' should not print shorthand versions\n"
+"    of directories which are relative to your home directory.  This means\n"
+"    that `~/bin' might be displayed as `/homes/bfox/bin'.  The -v flag\n"
+"    causes `dirs' to print the directory stack with one entry per line,\n"
+"    prepending the directory name with its position in the stack.  The -p\n"
+"    flag does the same thing, but the stack position is not prepended.\n"
+"    The -c flag clears the directory stack by deleting all of the elements.\n"
+"    \n"
+"    +N\tdisplays the Nth entry counting from the left of the list shown by\n"
+"    \tdirs when invoked without options, starting with zero.\n"
+"    \n"
+"    -N\tdisplays the Nth entry counting from the right of the list shown by\n"
+"    \tdirs when invoked without options, starting with zero."
+msgstr ""
+
+#: builtins.c:1364
+msgid ""
+" Toggle the values of variables controlling optional behavior.\n"
+"    The -s flag means to enable (set) each OPTNAME; the -u flag\n"
+"    unsets each OPTNAME.  The -q flag suppresses output; the exit\n"
+"    status indicates whether each OPTNAME is set or unset.  The -o\n"
+"    option restricts the OPTNAMEs to those defined for use with\n"
+"    `set -o'.  With no options, or with the -p option, a list of all\n"
+"    settable options is displayed, with an indication of whether or\n"
+"    not each is set."
+msgstr ""
+
+#: builtins.c:1377
+msgid ""
+" printf formats and prints ARGUMENTS under control of the FORMAT. FORMAT\n"
+"    is a character string which contains three types of objects: plain\n"
+"    characters, which are simply copied to standard output, character escape\n"
+"    sequences which are converted and copied to the standard output, and\n"
+"    format specifications, each of which causes printing of the next successive\n"
+"    argument.  In addition to the standard printf(1) formats, %b means to\n"
+"    expand backslash escape sequences in the corresponding argument, and %q\n"
+"    means to quote the argument in a way that can be reused as shell input.\n"
+"    If the -v option is supplied, the output is placed into the value of the\n"
+"    shell variable VAR rather than being sent to the standard output."
+msgstr ""
+
+#: builtins.c:1393
+msgid ""
+" For each NAME, specify how arguments are to be completed.\n"
+"    If the -p option is supplied, or if no options are supplied, existing\n"
+"    completion specifications are printed in a way that allows them to be\n"
+"    reused as input.  The -r option removes a completion specification for\n"
+"    each NAME, or, if no NAMEs are supplied, all completion specifications."
+msgstr ""
+
+#: builtins.c:1405
+msgid ""
+" Display the possible completions depending on the options.  Intended\n"
+"    to be used from within a shell function generating possible completions.\n"
+"    If the optional WORD argument is supplied, matches against WORD are\n"
+"    generated."
+msgstr ""
+"ðÏËÁÚÙ×ÁÅÔ ×ÏÚÍÏÖÎÙÅ ÄÏÐÏÌÎÅÎÉÑ × ÚÁ×ÉÓÉÍÏÓÔÉ ÏÐÃÉÊ. ðÒÅÄÐÏÌÁÇÁÅÔÓÑ,\n"
+"    ÞÔÏ ÂÕÄÅÔ ÉÓÐÏÌØÚÏ×ÁÔØÓÑ ×ÎÕÔÒÉ ÆÕÎËÃÉÊ ËÏÍÁÎÄÎÏÇÏ ÉÎÔÅÒÐÒÅÔÁÔÏÒÁ, ÇÅÎÅÒÉÒÕÀÝÅÊ ×ÏÚÍÏÖÎÙÅ ÄÏÐÏÌÎÅÎÉÑ.\n"
+"    åÓÌÉ ÎÅÏÂÑÚÁÔÅÌØÎÙÊ ÁÒÇÕÍÅÎÔ óìï÷ï ÂÙÌ ÉÓÐÏÌØÚÏ×ÁÎ, ÔÏ ÂÕÄÕÔ ÓÇÅÎÅÒÉÒÏ×ÁÎÙ ÔÏÌØËÏ ÓÏ×ÐÁÄÅÎÉÑ Ó óìï÷ï."
+
diff --git a/shell.c b/shell.c
index 1a4c001702f9b4bfce10a30fe5e838689834dde5..a28442c95f1af34cfddf8f65ec69b7f77219a759 100644 (file)
--- a/shell.c
+++ b/shell.c
@@ -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++;
     }
 
index 6d07c78f589d9f5f3b3eec1cc0b8f942d90198ab..1a4c001702f9b4bfce10a30fe5e838689834dde5 100644 (file)
--- a/shell.c~
+++ b/shell.c~
@@ -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
diff --git a/sig.c~ b/sig.c~
new file mode 100644 (file)
index 0000000..953ca43
--- /dev/null
+++ b/sig.c~
@@ -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 */
diff --git a/subst.c b/subst.c
index d023294b381aed57fcc0862f991701ea0a9a1ade..7950eed4076091b5fc2e25fde74be91198e1ecd9 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -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;
index 45bb54d870203ede4e6cdc505b7f1bc39f592f08..93939f199121c043e2db71f4a566221ce3f56766 100644 (file)
--- a/subst.c~
+++ b/subst.c~
@@ -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;
index a31c5b8cf402ad42f1fb1b9cec9d87d0b0facac0..adfbb9b42b4f310cd837de45f616e99d987e1b8f 100644 (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>
index 89cee53bfafc6dd45eb6bd0b5b5cc21838cedaba..46b07e3768f101c0c716957411a4ff0788dc33ec 100644 (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 */
 
index 3efcf32d68e9722024b6ca9d67f9e81b2aa5ac04..72ec06a2c1fd8dde92acea5e8ac773e35f1d061b 100755 (executable)
@@ -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
 
index 904467b5ca935d47079af7b874e1e20bc57ea5a2..a2263486b22e4e53e57f385ebf5caf0a7ef574e0 100644 (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'>
index b25fbe3171d8b9310ca940dc0883d254527f1220..c2201af3cf42070ecedd62c100b71e792e25a894 100644 (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' )"
diff --git a/trap.c b/trap.c
index e3ff2cbae14754cbd4b009cab71d00a68a8643e6..07b64dfdfabb7b96cb4d1894635df5c4d17b73cb 100644 (file)
--- a/trap.c
+++ b/trap.c
@@ -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
diff --git a/trap.c~ b/trap.c~
index 1125534a06a26c965c1ded17de749fa675bd70f7..7dcc0e063fe1be012b35151e32e64765f04d4b22 100644 (file)
--- a/trap.c~
+++ b/trap.c~
@@ -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